.NET检查两个IEnumerable <t>是否具有相同的元素</t>

时间:2010-10-28 10:47:56

标签: c# .net linq list set

  

可能重复:
  Comparing two collections for equality

我需要验证两个IEnumerable<T>列表是否具有相同的元素,不一定是相同的顺序。

我的目标是.NET 3.5。

以下是测试。问题是,HasSameElements()应该如何实施?

var l1 = new[]{1,2,3};
var l2 = new[]{3,1,2};

bool rez1 = l1.HasSameElements(l2);//should be true

var l3 = new[]{1,2,3,2};
var l4 = new[]{3,1,2,2};
bool rez2 = l3.HasSameElements(l4);//should be true

var l5 = new[]{1,2,3,2};
var l6 = new[]{1,2,3};
bool rez3 = l5.HasSameElements(l6);//should be false

附加说明:

  • 在示例中,我使用IEnumerable,但T可以是任何东西。 T必须实施IComparable吗?

  • Enumerable.SequenceEquals()本身不起作用,它期望元素的顺序相同。

  • 以下是HasElements的模板:

[只是一些占位符文本作为Markdown'代码格式化'错误的解决方法]

public static class Extensions {
    public static bool HasElements(this IEnumerable<T> l1, IEnumerable<T> l2){
        throw new NotImplementedException();
    } 
}

5 个答案:

答案 0 :(得分:4)

只需构建一个字典,将每个对象映射到它在序列中出现的次数,然后检查生成的字典是否相等。

下面:

static class EnumerableExtensions {
    public static bool HasSameElementsAs<T>(
        this IEnumerable<T> first,
        IEnumerable<T> second
    ) {
        var firstMap = first
            .GroupBy(x => x)
            .ToDictionary(x => x.Key, x => x.Count());
        var secondMap = second
            .GroupBy(x => x)
            .ToDictionary(x => x.Key, x => x.Count());
        return 
            firstMap.Keys.All(x =>
                secondMap.Keys.Contains(x) && firstMap[x] == secondMap[x]
            ) &&
            secondMap.Keys.All(x =>
                firstMap.Keys.Contains(x) && secondMap[x] == firstMap[x]
            );
    }
}

显然,重复的代码可以重构为辅助方法,但这只是混淆了这个想法。您可以获得幻想并接受IEqualityComparer GroupBy操作。此外,您应该通过添加null防护来生成代码,而不是。

答案 1 :(得分:3)

虽然基于Cristi的基于Except的方法更加出色,但您可能会侥幸逃脱:

source.Sort().SequenceEqual(target.Sort());

如果是单元测试,我不会担心性能。当然,您需要确保您的排序稳定。

答案 2 :(得分:0)

使用:

 return  l2.Count() == l1.Count() && l1.Intersect(l2).Count() == l2.Count();

您也可以传递自定义比较器。

public static class Extensions
{
    public static bool HasElements(
        this IEnumerable<T> l1, 
        IEnumerable<T> l2,
        IEqualityComparer<T> comparaer)
    {
        l2.Count() == l1.Count() && 
        return l1.Intersect(l2, comparer).Count() == l2.Count();
    } 
}

答案 3 :(得分:0)

我会做这样的事情

 public static bool HasSameElements<T>(this IEnumerable<T> source, IEnumerable<T> target)
 {
     return (source.Count() == target.Count() && source.All(a => target.Contains(a)));
 }

答案 4 :(得分:0)

因为输入可能包含重复项,所以不能使用Except。一种算法是:

if the lists contain a different number of elements return false

make a copy of listA
foreach element in listB 
  if the element exists in copyA remove the first match from copyA
  otherwise return false

对于实现,您可以查看FluentAssert中.ShouldBeEqualTo() method的逻辑。