按类型合并序列使用LINQ

时间:2010-03-13 23:46:13

标签: c# linq loops

我想用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,每个IEnumerable为value1ByType。像这样:

// 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中执行此操作?

4 个答案:

答案 0 :(得分: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; });

但是有很多方法可能出错,它引出了一个问题 - 为什么这些数据结构中的数据呢?你能解决这个问题吗?你是如何在第二个数据结构中使用恰当数量的引用到第一个中的元素的?

答案 1 :(得分:1)

我很确定@ 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<int, int>

答案 2 :(得分:0)

您可以做的是用以下内容替换第一部分:

var value1TypeEnumerators = value1ByType.ToList();

而不是使用枚举器。

答案 3 :(得分:0)

如果我不关心表现,我也可以写:

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);

我使用了zip方法from a stackoverflow community wiki。我没有使用c#4.0 zip method

对此进行测试