【问题标题】:Merging sequences by type With LINQ使用 LINQ 按类型合并序列
【发布时间】:2010-03-13 23:46:12
【问题描述】:

我想用 LINQ 来转换这个

IEnumerable<int>[] value1ByType = new IEnumerable<int>[3];
value1ByType[0]= new [] { 0};
value1ByType[1]= new [] {10,11};
value1ByType[2]= new [] {20};

var value2ToType = new Dictionary<int,int> {
{100,0},
{101,1},
{102,2},
{103,1}};

到这里

var value2ToValue1 = new Dictionary<int,int> { 
{100, 0},
{101,10},
{102,20},
{103,11}};

有没有办法用 LINQ 做到这一点?如果没有 LINQ,我将使用多个 IEnumerator,一个用于 value1ByType 的每个 IEnumerable。像这样:

// create enumerators
var value1TypeEnumerators = new List<IEnumerator<int>>();
for (int i = 0; i < value1ByType.Length; i++)
{
    value1TypeEnumerators.Add(value1ByType[i].GetEnumerator());
    value1TypeEnumerators[i].MoveNext();
}

// create wanted dictionary
var value2ToValue1 = new Dictionary<int, int>();
foreach (var item in Value2ToType)
{
    int value1=value1TypeEnumerators[item.Value].Current;
    value2ToValue1.Add(item.Key, value1);
    value1TypeEnumerators[item.Value].MoveNext();
}

知道如何在 LINQ 中执行此操作吗?

【问题讨论】:

    标签: c# linq loops


    【解决方案1】:

    不纯粹,但你至少可以做到……

    var enumerators = value1ByType.Select(v => v.GetEnumerator()).ToArray();
    var value2ToValue1 = value2ToType
                            .ToDictionary(x => x.Key, x => { enumerators[x.Value].MoveNext(); return enumerators[x.Value].Current; });
    

    但是有很多方法可能会出错,这就引出了一个问题——为什么这些数据结构中的数据仍然存在?而你能解决这个问题吗?您是如何在第二个数据结构中对第一个数据结构中的元素进行正确数量的引用的?

    【讨论】:

    • 我从对象(=value2)中将一个变量(=type)存储在数据库表中。之后,我将自动生成的 id (=value1) 与类型一起加载并构建 objectToID 字典。
    • @Janko - 也许一些代码 sn-ps 可以帮助我们理解......你的类和表格是什么样的?
    • 如果我在你的代码中使用 GetNext Extension of Fedes 答案,那么你的代码对我来说是最易读的(也是最快的),所以我将你的答案设置为公认的答案。
    • 也许我会用原始问题发布另一个问题。
    【解决方案2】:

    我很确定@Hightechrider 的解决方案比这个解决方案性能最好,但如果你真的喜欢语法糖的方式,你可以这样做:

    public IDictionary<int, int> MergeSequences(IEnumerable<int>[] value1ByType, Dictionary<int, int> value2ToType)
    {
        int pos = 0;
        var value1ByTypePos = from byType in value1ByType
                              select new { Pos = pos++, Enumerator = byType.GetEnumerator() };
        return (from byType in value1ByTypePos
                join toType in value2ToType
                on byType.Pos equals toType.Value
                select new { toType.Key, Value = byType.Enumerator.GetNext() })
               .ToDictionary(pair => pair.Key, pair => pair.Value);
    }
    

    我在 IEnumerator 接口中添加了一个扩展方法,如下所示:

    public static T GetNext<T>(this IEnumerator<T> enumerator)
    {
        if (!enumerator.MoveNext())
            throw new InvalidOperationException();
        return enumerator.Current;
    }
    

    现在您必须知道,这些解决方案中的任何一种都可能给您带来略微不同的结果,具体取决于字典中元素的枚举方式。例如,此代码的另一个有效结果是:

    var value2ToValue1 = new Dictionary<int,int> { 
        {100, 0},
        {103, 10},
        {102, 20},
        {101, 11}};
    

    请注意,现在 101 与 11 配对,103 与 10 配对。如果这是一个问题,那么在定义 value2ToType 变量时应该使用SortedDictionary&lt;int, int&gt;

    【讨论】:

      【解决方案3】:

      您可以确定的是将第一部分替换为以下内容:

      var value1TypeEnumerators = value1ByType.ToList();
      

      而不是使用枚举器。

      【讨论】:

        【解决方案4】:

        如果我不关心性能,我也可以写:

        var value2Ordered = Value2ToType.OrderBy(x => x.Value).Select(x=>x.Key);
        var value1Ordered = from item in value1ByType from subitem in item select subitem;
        var value2ToValue1 = value2Ordered.Zip(value1Ordered, (x, y) => new { Key = x, Value = y })
            .ToDictionary(item => item.Key, item => item.Value);
        

        我使用的是压缩方式from a stackoverflow community wiki。我没有用 c#4.0 zip method 测试这个

        【讨论】:

          猜你喜欢
          • 2012-06-10
          • 2016-08-14
          • 2017-11-05
          • 1970-01-01
          • 2019-02-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多