确定两个List <t>对象是否包含相同的值集的最佳方法是什么,即使它们的顺序不同?

时间:2015-10-20 19:50:36

标签: c# collections compare comparison

我有两个List<T>个对象(其中T对于两个对象都是相同的类型),我需要能够确定它们是否包含相同的值集,即使值不是& #39; t按相同顺序排列。

对象是否有任何内置机制来完成此任务,或者我是否需要编写自己的算法?

或许,我应该使用不同类型的集合,而不是List<T>

如果我要编写自己的算法,它可能包含以下步骤 - 如果我走这条路线,我会尝试在最终版本中对其进行优化:

  • 这两个集合是否包含相同数量的值?如果没有返回false。
  • 计算每个值在每个集合中出现的次数,如果计数不相等则返回false。
  • 如果我到达两个集合的末尾而没有任何值不等的数量,则返回true。

我知道这有一些注意事项,例如T必须具有可比性 - 我现在使用默认比较(例如.Equals()),并为通用类型定义了适当的约束

3 个答案:

答案 0 :(得分:1)

根据可用信息,我怀疑支持重复的最有效解决方案是

  • 比较两个列表的大小。如果不相等,则返回false。如果相等,
  • 对两个列表进行排序。如果您必须保留原始列表的顺序,请改为对列表进行排序。
  • 比较排序列表的每个位置的元素,如果给定位置的值不相等,则返回false。如果您已经比较了所有元素而没有找到差异,则返回true。

请注意,我假设在此操作期间有足够的内存可用于创建列表的排序副本(应该要求保存是必需的)。

答案 1 :(得分:1)

所以我们从一个简单的SetEquals开始,然后从那里开始。 HashSet已经有了这样一个方法的实现,它可以比较两个集合的相等性,所以我们可以创建一个包装器,以便我们可以将它用于任何类型的序列:

public static bool SetEquals<T>(this IEnumerable<T> first, IEnumerable<T> second,
    IEqualityComparer<T> comparer = null)
{
    return new HashSet<T>(second, comparer ?? EqualityComparer<T>.Default)
        .SetEquals(first);
}

接下来,为了说明你有一个包,而不是一个集合,我们可以只取你拥有的两个序列,对它们进行分组,并将其投影到一个包含项目的对中,以及匹配项目。如果我们为两个集合执行此操作,那么我们可以将这些对象序列比较为,并查看它们是否设置为相等。如果密钥计数对序列都设置为相等,那么原始序列是相同的:

public static bool BagEquals<T>(
    this IEnumerable<T> first,
    IEnumerable<T> second)
{
    Func<IEnumerable<T>, IEnumerable<KeyValuePair<T, int>>> groupItems =
        sequence => sequence.GroupBy(item => item,
            (key, items) => new KeyValuePair<T, int>(key, items.Count()));
    return groupItems(first)
        .SetEquals(groupItems(second));
}

答案 2 :(得分:1)

这是CollectionAssert.AreEquivalent的重新实现(参考代码用DotPeek反编译)但是它不是抛出异常而是返回一个bool。

inner.xsd