Quickest way to compare two List<>
比较两个大型(>50000个项目)最快(也是最不消耗资源)的是什么,结果有两个列表,如下所示:
目前,我正在使用list或ireadOnlyCollection,并在Linq查询中解决此问题:
1 2 | var list1 = list.Where(i => !list2.Contains(i)).ToList(); var list2 = list2.Where(i => !list.Contains(i)).ToList(); |
但这并没有我想的那么好。如果我需要处理大量的列表,有没有想过让这个过程更快、更少地占用资源?
使用
1 2 | var firstNotSecond = list1.Except(list2).ToList(); var secondNotFirst = list2.Except(list1).ToList(); |
我怀疑有些方法实际上比这快一点,但即使这样也比O(N*M)方法快得多。
如果要组合这些,可以使用上面的方法创建一个方法,然后创建一个RETURN语句:
1 | return !firstNotSecond.Any() && !secondNotFirst.Any(); |
更有效的方法是使用
1 2 | var inListButNotInList2 = list.Except(list2); var inList2ButNotInList = list2.Except(list); |
此方法是通过使用延迟执行来实现的。这意味着你可以写例如:
1 | var first10 = inListButNotInList2.Take(10); |
它也很有效,因为它内部使用
如果希望结果不区分大小写,则可以使用以下方法:
1 2 3 4 5 |
不是为了这个问题,但这里有一些代码可以比较列表中的相等与否!相同的对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public class EquatableList<T> : List<T>, IEquatable<EquatableList<T>> where T : IEquatable<T> /// <summary> /// True, if this contains element with equal property-values /// </summary> /// <param name="element">element of Type T</param> /// <returns>True, if this contains element</returns> public new Boolean Contains(T element) { return this.Any(t => t.Equals(element)); } /// <summary> /// True, if list is equal to this /// </summary> /// <param name="list">list</param> /// <returns>True, if instance equals list</returns> public Boolean Equals(EquatableList<T> list) { if (list == null) return false; return this.All(list.Contains) && list.All(this.Contains); } |
尝试这种方式:
1 2 | var difList = list1.Where(a => !list2.Any(a1 => a1.id == a.id)) .Union(list2.Where(a => !list1.Any(a1 => a1.id == a.id))); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | using System.Collections.Generic; using System.Linq; namespace YourProject.Extensions { public static class ListExtensions { public static bool SetwiseEquivalentTo<T>(this List<T> list, List<T> other) where T: IEquatable<T> { if (list.Except(other).Any()) return false; if (other.Except(list).Any()) return false; return true; } } } |
有时,您只需要知道两个列表是否不同,而不需要知道这些差异是什么。在这种情况下,考虑将这个扩展方法添加到项目中。请注意,列出的对象应该实现IEquatable!
用途:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public sealed class Car : IEquatable<Car> { public Price Price { get; } public List<Component> Components { get; } ... public override bool Equals(object obj) => obj is Car other && Equals(other); public bool Equals(Car other) => Price == other.Price && Components.SetwiseEquivalentTo(other.Components); public override int GetHashCode() => Components.Aggregate( Price.GetHashCode(), (code, next) => code ^ next.GetHashCode()); // Bitwise XOR } |
无论
注意我们如何编写gethashcode是非常重要的。为了正确实现
两个内容相同的列表仍然是不同的对象,将产生不同的哈希代码。既然我们希望这两个列表被平等对待,我们必须让
注意:这个奇怪的名称意味着这个方法不考虑列表中元素的顺序。如果您关心列表中元素的顺序,那么这个方法不适合您!
我用这段代码比较了两个拥有数百万条记录的列表。
这个方法不会花很多时间
1 2 3 4 5 6 7 8 9 10 | //Method to compare two list of string private List<string> Contains(List<string> list1, List<string> list2) { List<string> result = new List<string>(); result.AddRange(list1.Except(list2, StringComparer.OrdinalIgnoreCase)); result.AddRange(list2.Except(list1, StringComparer.OrdinalIgnoreCase)); return result; } |
如果只需要组合结果,这也会起作用:
1 2 3 |
其中t是lists元素的类型。
可能很有趣,但对我有用
string.join(",list1)!=string.join(",list2)
我认为这是一种简单易行的方法来比较两个列表元素
1 2 3 4 5 6 7 8 9 10 11 12 | x=[1,2,3,5,4,8,7,11,12,45,96,25] y=[2,4,5,6,8,7,88,9,6,55,44,23] tmp = [] for i in range(len(x)) and range(len(y)): if x[i]>y[i]: tmp.append(1) else: tmp.append(0) print(tmp) |
这是你能找到的最好的解决办法
1 | var list3 = list1.Where(l => list2.ToList().Contains(l)); |