又是一个比较列表的问题。

List<MyType> list1;
List<MyType> list2;

我需要检查它们是否具有相同的元素,而不管它们在列表中的位置。每个MyType对象可以在列表中出现多次。是否有一个内置函数来检查这个?如果我保证每个元素在列表中只出现一次呢?

编辑:伙计们,谢谢你们的回答,但我忘了补充一些东西,每个元素的出现次数应该是相同的两个列表。


当前回答

除了Guffa的答案之外,您还可以使用这个变体来获得更简洁的符号。

public static bool ScrambledEquals<T>(this IEnumerable<T> list1, IEnumerable<T> list2)
{
  var deletedItems = list1.Except(list2).Any();
  var newItems = list2.Except(list1).Any();
  return !newItems && !deletedItems;          
}

其他回答

除了Guffa的答案之外,您还可以使用这个变体来获得更简洁的符号。

public static bool ScrambledEquals<T>(this IEnumerable<T> list1, IEnumerable<T> list2)
{
  var deletedItems = list1.Except(list2).Any();
  var newItems = list2.Except(list1).Any();
  return !newItems && !deletedItems;          
}

这是一个有点难的问题,我认为可以简化为:“测试两个列表是否互为排列。”

我认为其他人提供的解决方案只是说明这两个列表是否包含相同的唯一元素。例如,这是一个必要但不充分的测试 {1,1,2,3}不是{3,3,1,2}的排列 尽管它们的计数相等,而且它们含有相同的不同元素。

我相信这应该是可行的,尽管它不是最有效的:

static bool ArePermutations<T>(IList<T> list1, IList<T> list2)
{
   if(list1.Count != list2.Count)
         return false;

   var l1 = list1.ToLookup(t => t);
   var l2 = list2.ToLookup(t => t);

   return l1.Count == l2.Count 
       && l1.All(group => l2.Contains(group.Key) && l2[group.Key].Count() == group.Count()); 
}

如上所述,这个问题模棱两可。声明:

... 它们都有相同的元素,不管它们在列表中的位置如何。 每个MyType对象可以在列表中出现多次。

没有指示是否要确保两个列表具有相同的对象集,还是具有相同的不同的对象集。

如果你想确保集合有完全相同的成员集,不管顺序如何,你可以使用:

// lists should have same count of items, and set difference must be empty
var areEquivalent = (list1.Count == list2.Count) && !list1.Except(list2).Any();

如果你想确保两个集合有相同的不同的成员集(其中任何一个的重复都被忽略),你可以使用:

// check that [(A-B) Union (B-A)] is empty
var areEquivalent = !list1.Except(list2).Union( list2.Except(list1) ).Any();

使用集合操作(Intersect、Union、Except)比使用Contains等方法更有效。在我看来,它也更好地表达了您的查询的期望。

编辑:既然你已经澄清了你的问题,我可以说你想使用第一种形式——因为重复很重要。这里有一个简单的例子来证明你得到了你想要的结果:

var a = new[] {1, 2, 3, 4, 4, 3, 1, 1, 2};
var b = new[] { 4, 3, 2, 3, 1, 1, 1, 4, 2 };

// result below should be true, since the two sets are equivalent...
var areEquivalent = (a.Count() == b.Count()) && !a.Except(b).Any(); 

认为这应该是你想要的:

list1.All(item => list2.Contains(item)) &&
list2.All(item => list1.Contains(item));

如果你想要它是不同的,你可以把它改为:

list1.All(item => list2.Contains(item)) &&
list1.Distinct().Count() == list1.Count &&
list1.Count == list2.Count

如果你不关心出现的次数,我会这样做。使用哈希集将比简单迭代提供更好的性能。

var set1 = new HashSet<MyType>(list1);
var set2 = new HashSet<MyType>(list2);
return set1.SetEquals(set2);

这将需要你重写. gethashcode()并在MyType上实现IEquatable<MyType>。