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

可能重复:
比较两个集合是否相等

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

我的目标是.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 l1, IEnumerable l2){ throw new NotImplementedException(); } } 

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

这里:

 static class EnumerableExtensions { public static bool HasSameElementsAs( this IEnumerable first, IEnumerable 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] ); } } 

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

虽然基于Cristi的基于Except的方法更好,但您可能会逃脱:

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

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

使用:

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

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

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

我会做这样的事情

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

因为输入可以包含重复项,所以不能使用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()方法的逻辑。