C# - Dictionary <int,sortedlist <int,=“”list <int =“”>&gt;&gt;的交叉点

时间:2015-04-30 08:19:29

标签: c# .net linq dictionary intersection

请考虑以下代码:

Dictionary<int, SortedList<int, List<int>>> ddl1 = new Dictionary<int, SortedList<int, List<int>>>();

ddl1.Add(1, new SortedList<int,List<int>>());
ddl1[1].Add(2, new List<int>());
ddl1[1][2].Add(3);
ddl1[1][2].Add(4);
ddl1[1][2].Add(5);

ddl1[1].Add(3, new List<int>());
ddl1[1][3].Add(3);
ddl1[1][3].Add(4);
ddl1[1][3].Add(5);


ddl1.Add(2, new SortedList<int, List<int>>());
ddl1[2].Add(2, new List<int>());
ddl1[2][2].Add(3);
ddl1[2][2].Add(4);
ddl1[2][2].Add(5);


Dictionary<int, SortedList<int, List<int>>> ddl2 = 
         new Dictionary<int, SortedList<int, List<int>>>();

ddl2.Add(1, new SortedList<int, List<int>>());

ddl2[1].Add(3, new List<int>());
ddl2[1][3].Add(3);
ddl2[1][3].Add(4);



ddl2.Add(2, new SortedList<int, List<int>>());
ddl2[2].Add(2, new List<int>());
ddl2[2][2].Add(3);

我希望得到这两个复杂词典的交集。结果应包含

1 { 3 {3,4} }
2 { 2 {3 } }

有人可以帮我解决这个LINQ问题吗?此外,它是否比手动foreach和.contains方法更有效?提前谢谢!

3 个答案:

答案 0 :(得分:2)

简而言之,最好用foreach手动完成。我想如果你真的想通过LINQ这样做,你将不得不创建一些自定义IEqualityComparer,这不仅仅是一个手动foreach解决方案的编码工作量。

但是,如果您通过LINQ进行,则可能会受益于PLINQ。除此之外,我不明白为什么LINQ解决方案会更快。

但是,您当然可以使用Intersect。但请记住,每当您按照评论中的建议调用ToDictionary时,您将创建一个新的字典,这是耗费时间和内存的。

因此,假设您仍然需要SortedList,这是我能想到的最佳解决方案。如果没有,请用通常的字典替换。

var result = new Dictionary<int, SortedList<int, List<int>><();
foreach (var key1 in ddl1.Keys.Intersect(ddl2.Keys))
{
    var subList1 = ddl1[key1];
    var subList2 = ddl2[key1];
    var common1 = new SortedList<int, List<int>>();
    result.Add(key1, common1);
    foreach (var key2 in subList1.Keys.Intersect(subList2.Keys))
    {
        var subList1L2 = subList1[key2];
        var subList2L2 = subList2[key2];
        var common2 = subList1L2.Intersect(subList2L2).ToList();
        if (common2.Count > 0) common1.Add(key2, common2);
    }
}

答案 1 :(得分:1)

诀窍是将字典键两个词典加入SortedList键:

var q1 = from d1 in ddl1
         from sl1 in d1.Value
         select new { d1.Key, sl1 };
var q2 = from d2 in ddl2
         from sl2 in d2.Value
         select new { d2.Key, sl2 };

var q = from ds1 in q1
        join ds2 in q2
        on         new { key1 = ds1.Key, key2 = ds1.sl1.Key } 
            equals new { key1 = ds2.Key, key2 = ds2.sl2.Key } 
        select new
        { 
            key1 = ds1.Key,
            key2 = ds1.sl1.Key,
            Intersect = ds1.sl1.Value.Intersect(ds2.sl2.Value)
        };

子查询(q1, q2)将字典展平为列表列表,因此对于连接,可以组合字典键和列表键。

现在,您可以首先使用q2.AsParallel()然后q1.AsParallel()来衡量并行化是否确实提高了性能。

答案 2 :(得分:0)

试试这个方法:

public static IDictionary<int, SortedList<int, List<int>>> Intersect(IDictionary<int, SortedList<int, List<int>>> x, IDictionary<int, SortedList<int, List<int>>> y) {
    IDictionary<int, SortedList<int, List<int>>> one = x.Keys.Intersect(y.Keys).ToDictionary(k => k, k => x[k]);
    foreach (KeyValuePair<int, SortedList<int, List<int>>> kvp in one.ToList()) {
        one[kvp.Key] = new SortedList<int,List<int>>(kvp.Value.Keys.Intersect(y[kvp.Key].Keys).ToDictionary(k => k, k => y[kvp.Key][k]));
    }
    return one;
}