确定两个List 对象是否包含相同的值集,即使它们的顺序不同,最好的方法是什么?
我有两个List
对象(其中T
对于两个对象都是相同的类型),我需要能够确定它们是否包含相同的值集,即使值不是相同的顺序。
对象是否有任何内置机制来完成此任务,或者我是否需要编写自己的算法?
或许,我应该使用不同类型的集合,而不是List
?
如果我要编写自己的算法,它可能包含以下步骤 – 如果我走这条路线,我会尝试在最终版本中优化它:
- 这两个集合是否包含相同数量的值? 如果没有返回false。
- 计算每个值在每个集合中出现的次数,如果计数不相等则返回false。
- 如果我到达两个集合的末尾而没有值计数的任何不等,则返回true。
我知道这有一些注意事项,比如T必须具有可比性 – 我现在使用默认比较(例如.Equals()
),并为generics类型定义了适当的约束。
根据可用的信息,我怀疑支持重复的最有效的解决方案是
- 比较两个列表的大小。 如果不相等,则返回false。 如果相等,
- 对两个列表排序。 如果必须保留原始列表的顺序,请改为对列表进行排序。
- 比较排序列表的每个位置的元素,如果给定位置的值不相等则返回false。 如果您已经比较了所有元素而没有找到差异,则返回true。
请注意,我假设在此操作期间有足够的内存可用于创建列表的已排序副本(应将订单保留作为要求)。
所以我们从一个简单的SetEquals
,然后从那里开始。 HashSet
已经有了这样一个方法的实现,它可以比较两个集合的相等性,所以我们可以创建一个包装器,以便我们可以将它与任何类型的序列一起使用:
public static bool SetEquals(this IEnumerable first, IEnumerable second, IEqualityComparer comparer = null) { return new HashSet (second, comparer ?? EqualityComparer .Default) .SetEquals(first); }
接下来,为了说明你有一个包,而不是一个集合,我们可以只取你拥有的两个序列,对它们进行分组,并将其投影到一个包含项目和匹配项目数量的对中。 如果我们为两个集合执行此操作,那么我们可以将这些对象序列作为集合进行比较 ,并查看它们是否设置为相等。 如果密钥计数对序列都设置为相等,那么原始序列是相同的:
public static bool BagEquals( this IEnumerable first, IEnumerable second) { Func, IEnumerable>> groupItems = sequence => sequence.GroupBy(item => item, (key, items) => new KeyValuePair(key, items.Count())); return groupItems(first) .SetEquals(groupItems(second)); }
这是CollectionAssert.AreEquivalent
的重新实现(参考代码用DotPeek反编译)但是它不是抛出exception而是返回bool。
public class CollectionMethods { public static bool AreEquivalent(ICollection expected, ICollection actual) { //We can do a few quick tests we can do to get a easy true or easy false. //Is one collection null and one not? if (Object.ReferenceEquals(expected, null) != Object.ReferenceEquals(actual, null)) return false; //Do they both point at the same object? if (Object.ReferenceEquals(expected, actual)) return true; //Do they have diffrent counts? if (expected.Count != actual.Count) return false; //Do we have two empty collections? if (expected.Count == 0) return true; //Ran out of easy tests, now have to do the slow work. int nullCount1; Dictionary
- 在3层架构中使用BAL?如何从DAL调用方法到BAL
- 没有明确的ServicePointManager.SecurityProtocol调用,在.NET 4.7中没有协商TLS 1.2
- 加密BouncyCastle RSA密钥对并存储在SQL2008数据库中
- 在C#中打印控件的内容?
- 配置log4net以写入不同的日志文件,没有配置文件
- entity framework:StoreGeneratedPattern =“Computed”属性
- 在Windows 8 Metro App中为用户contaclist添加联系人
- 我应该使用Invoke或SynchronizationContext来更新另一个线程的表单控件吗?
- 如何在Winform C#上创建带圆角/边缘的按钮?