找到 2 个 IEnumerables 之间差异的有效方法

Efficient way to find the difference between 2 IEnumerables

我有

IEnumerable<Tuple<string, string>> allInfo

IEnumerable<string> info1dim。有什么方法可以有效地找到 info1dimallInfo 的第一个暗淡之间的差异。例如:

allInfo = {<"data1", "addinfo1">, <"data2", "addinfo2">, <"data3", "addinfo3">"

info1dim = {"data3", "data1", "data4"}

我期望的结果是

{"diff4"}

最有效的方法是什么? 我不想 运行 两个循环。 IEnumerables 很大(~100000 个元素)

也许是这样的?

var diff = info1dim.Where(x => allInfo.Any(c => c.Item1 == x) == false);

如果您将 IEnumerable<Tuple<string, string>> 存储在 Dictionary<string,string> 中,它会变得更快!那么你可以写:

Dictionary<string,string> allInfo;
IEnumerable<string> info1dim;
var diff = info1dim.Where(x => allInfo.ContainsKey(x) == false);

您可以像这样使用 LINQ Except()

info1dim.Except(allInfo.Select(i => i.Item1));

请注意,Except() 在内部使用了 HashSet<T>(如 here 所述),所以这仍然是 O(n)。

将您的 info1dim 加载到 HashSet 中并使用 Remove foreach item in allInfo :

// n: size of info1dim ; m: size of allInfo
var diff = new HashSet<string> (info1dim); // O(n)
foreach (var tuple in allInfo)  // O(m)
    diff.Remove (tuple.Item1);  // O(1)

在 Ollie 的回答之前,我不记得有 ExceptWith 存在;在 source reference ExceptWith 验证后基本上做同样的事情(foreach -> Remove)所以应该更好;我保持我的代码原样作为信息支持强硬

C# HashSet 集合有 ExceptWithUnionWithIntersectWith 方法。你想要的可以像这样完成。

        var set1 = new HashSet<string>(allinfo.Select(t => t.Item1));
        var set2 = new HashSet<string>(info1dim);

        var set1_but_not_set2 = new HashSet<string>(set1);
        set1_but_not_set2.ExceptWith(set2);

        var set2_but_not_set1 = new HashSet<string>(set2);
        set2_but_not_set1.ExceptWith(set1);

不过要小心,HashSet 是一个可变集合,这些函数会更改集合。您在这里有 O(n) 个操作。构造 HashSet 对象需要迭代; ExceptWith 操作也是如此。