C# 比较两个列表<;T>;对象以实现相等,忽略顺序

C# 比较两个列表<;T>;对象以实现相等,忽略顺序,c#,list,comparison,equals,C#,List,Comparison,Equals,还有一个问题 List<MyType> list1; List<MyType> list2; 列表列表1; 清单2; 我需要检查它们是否都有相同的元素,而不管它们在列表中的位置如何。每个MyType对象可能在列表中出现多次。是否有一个内置函数来检查这一点?如果我保证每个元素在列表中只出现一次会怎么样 编辑:伙计们,谢谢你们的回答,但我忘了添加一些东西,每个元素在两个列表中出现的次数应该是相同的。认为这应该满足您的要求: list1.All(item => lis

还有一个问题

List<MyType> list1;
List<MyType> list2;
列表列表1;
清单2;
我需要检查它们是否都有相同的元素,而不管它们在列表中的位置如何。每个MyType对象可能在列表中出现多次。是否有一个内置函数来检查这一点?如果我保证每个元素在列表中只出现一次会怎么样


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

认为这应该满足您的要求:

list1.All(item => list2.Contains(item)) &&
list2.All(item => list1.Contains(item));
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)) &&
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);
var set1=新哈希集(列表1);
var set2=新的HashSet(列表2);
返回set1.SetEquals(set2);

这将需要您重写
.GetHashCode()
并在
MyType

上实现
IEquatable
,这是一个稍微困难的问题,我认为可以简化为:“测试两个列表是否相互排列。”

我相信其他人提供的解决方案只表明这两个列表是否包含相同的独特元素。例如,这是一个必要但不充分的测试
{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()); 
}
静态布尔值置换(IList列表1、IList列表2)
{
if(list1.Count!=list2.Count)
返回false;
var l1=list1.ToLookup(t=>t);
var l2=list2.ToLookup(t=>t);
返回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();
如果要确保两个集合具有相同的不同成员集(忽略其中任何一个集合中的重复项),可以使用:

// 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
等方法效率更高。在我看来,它也更好地表达了您对查询的期望

编辑:既然你已经澄清了你的问题,我可以说你想使用第一种形式——因为重复很重要。下面是一个简单的示例,演示如何获得所需的结果:

list1.All(item => list2.Contains(item)) &&
list2.All(item => list1.Contains(item));
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(); 

如果您希望它们真正相等(即相同的项目和每个项目的相同数量),我认为最简单的解决方案是在比较之前进行排序:

Enumerable.SequenceEqual(list1.OrderBy(t => t), list2.OrderBy(t => t))
编辑: 这是一个性能更好(大约快十倍)的解决方案,只需要
IEquatable
,而不需要
IComparable

public static bool ScrambledEquals<T>(IEnumerable<T> list1, IEnumerable<T> list2) {
  var cnt = new Dictionary<T, int>();
  foreach (T s in list1) {
    if (cnt.ContainsKey(s)) {
      cnt[s]++;
    } else {
      cnt.Add(s, 1);
    }
  }
  foreach (T s in list2) {
    if (cnt.ContainsKey(s)) {
      cnt[s]--;
    } else {
      return false;
    }
  }
  return cnt.Values.All(c => c == 0);
}
publicstaticboolscrambledequals(IEnumerablest1,IEnumerablest2){
var cnt=新字典();
foreach(列表1中的ts){
如果(cnt.ContainsKey){
cnt[s]++;
}否则{
cnt.添加(s,1);
}
}
foreach(列表2中的ts){
如果(cnt.ContainsKey){
cnt[s]-;
}否则{
返回false;
}
}
返回cnt.Values.All(c=>c==0);
}
编辑2: 要将任何数据类型作为键处理(例如Frank Tzanabetis指出的可为null的类型),您可以为字典创建一个采用a的版本:

public static bool ScrambledEquals<T>(IEnumerable<T> list1, IEnumerable<T> list2, IEqualityComparer<T> comparer) {
  var cnt = new Dictionary<T, int>(comparer);
  ...
publicstaticboolscrambledequals(IEnumerable列表1、IEnumerable列表2、IEqualityComparer比较器){
var cnt=新字典(比较器);
...

除了Guffa的答案之外,您还可以使用这个变体来表示更为简捷的符号

publicstaticboolscrambledequals(此IEnumerable列表1、IEnumerable列表2)
{
var deletedItems=list1.Except(list2.Any();
var newItems=list2.Except(list1.Any();
return!newItems&!deletedItems;
}
试试这个

使用以下代码,您可以根据需要比较一个或多个字段以生成结果列表。结果列表将仅包含修改的项

//已使用veriables
List diffList=新列表();
List GOTRUSTLIST=新列表();
//比较MyList中的第一个字段
gotResultList=MyList1.Where(a=>!MyList2.Any(a1=>a1.MyListField1==a.MyListField1)).ToList()。除了(gotResultList.Where(a=>!MyList2.Any(a1=>a1.MyListField1==a.MyListField1))。ToList();
//生成结果列表
AddRange(gotResultList);
//比较MyList中的第二个字段
gotResultList=MyList1.Where(a=>!MyList2.Any(a1=>a1.MyListFieldd2==a.MyListFieldd2)).ToList()。除了(gotResultList.Where(a=>!MyList2.Any(a1=>a1.MyListFieldd2==a.MyListFieldd2))).ToList();
//生成结果列表
AddRange(gotResultList);
Show(diffList.Count.ToString);
我使用这种方法)

公共委托布尔比较值(T1值1,T2值2);
公共静态布尔CompareTowarray(此IEnumerable array1、IEnumerable array2、CompareValue CompareValue)
{
返回array1.Select(item1=>array2.Any(item2=>compareValue(item1,item2)).All(search=>search)
&&array2.Select(item2=>array1.Any(item1=>compareValue(item1,item2)).All(search=>search);
}
这对我很有效:
如果要比较依赖于单个实体(如
ID
)的两个对象列表,并且需要与该条件匹配的第三个列表,则可以执行以下操作:

var list3 = List1.Where(n => !List2.select(n1 => n1.Id).Contains(n.Id));

请参阅:

list2可能包含额外的项。@recursive:edite