C# 自定义IEqualityComparer可以比使用.Where()+;更快地从两个列表中获取不同的对象。任何()
所以我有两个对象列表,对象有多个字段,但我只想根据其中两个字段来区分它们 要显示图片,object KeyAndValue由Key和Tag字段组成,因此:C# 自定义IEqualityComparer可以比使用.Where()+;更快地从两个列表中获取不同的对象。任何(),c#,list,object,distinct,iequalitycomparer,C#,List,Object,Distinct,Iequalitycomparer,所以我有两个对象列表,对象有多个字段,但我只想根据其中两个字段来区分它们 要显示图片,object KeyAndValue由Key和Tag字段组成,因此: list1 = { obj1(key=1,tag=A), obj2(key=2,tag=A) } list2 = { obj3(key=1,tag=A), obj4(key=2,tag=B) } 我目前正在使用: list1.Where(x => !list2.Any(y => y.key == x.key)).ToList()
list1 = { obj1(key=1,tag=A), obj2(key=2,tag=A) }
list2 = { obj3(key=1,tag=A), obj4(key=2,tag=B) }
我目前正在使用:
list1.Where(x => !list2.Any(y => y.key == x.key)).ToList();
正确的结果是:作为obj3的obj1、obj2和obj4与obj1具有相同的键和标记
我试图实现的是加快这个过程,因为对于很多对象来说,这需要花费太长的时间。我发现定制的IEqualityComparer可以在这里提供帮助,所以我基于
看起来是这样的:
class KeyComparer : IEqualityComparer<KeyAndValue>
{
public bool Equals(KeyAndValue x, KeyAndValue y)
{
if (Object.ReferenceEquals(x, y))
return true;
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
return x.key == y.key && x.tag == y.tag;
}
public int GetHashCode(KeyAndValue keyAndValue)
{
if (Object.ReferenceEquals(keyAndValue, null))
return 0;
int hashKeyAndValueKey = keyAndValue.key == null ? 0 : keyAndValue.key.GetHashCode();
int hashKeyAndValueTag = keyAndValue.tag == null ? 0 : keyAndValue.tag.GetHashCode();
return hashKeyAndValueKey ^ hashKeyAndValueTag;
}
}
list1.Except(list2, new KeyComparer()).ToList();
不幸的是,它只从列表2中删除重复项。似乎它甚至没有触及列表1,我不知道这是否是我的自定义比较器的错误,我使用它的方式,或者我应该使用另一种方法。我一直在查看其他问题,但找不到有效的答案(或者至少是我知道如何正确实施的答案)。我认为您不需要
,只需要。你想两者都有不同的值吗
var distinctValues = list1.Union(list2).Distinct();
您需要在KeyAndValue
中实现GetHashCode
/Equals
,或者使用比较器按键和值比较对象
(下面是老东西)
不确定我是否正确理解了这个问题。除了创建一个新的IEnumerable并列出一个新列表之外,您是否还没有意识到这一点
尝试:
也许还有:
var list2AdditionalItems = list2.Except(list1, new KeyComparer()).ToList();
另一个观察。在此代码中:
list1.Where(x => !list2.Any(y => y.key == x.key)).ToList();
你只检查钥匙。如果需要此行为,应相应地编写比较器:
class KeyComparer : IEqualityComparer<KeyAndValue>
{
public bool Equals(KeyAndValue x, KeyAndValue y)
{
if (ReferenceEquals(x, y))
return true;
if (ReferenceEquals(x, null) || ReferenceEquals(y, null))
return false;
return x.key == y.key;
}
public int GetHashCode(KeyAndValue keyAndValue)
{
if (ReferenceEquals(keyAndValue, null))
return 0;
return keyAndValue.key == null ? 0 : keyAndValue.key.GetHashCode();
}
}
类键比较器:IEqualityComparer
{
公共布尔等于(KeyAndValue x,KeyAndValue y)
{
if(ReferenceEquals(x,y))
返回true;
if(ReferenceEquals(x,null)| | ReferenceEquals(y,null))
返回false;
返回x.key==y.key;
}
public int GetHashCode(KeyAndValue KeyAndValue)
{
if(ReferenceEquals(keyAndValue,null))
返回0;
return keyAndValue.key==null?0:keyAndValue.key.GetHashCode();
}
}
最后但并非最不重要:当你需要表现时,考虑使用字典代替.< /P> < P>作为第一次评论中提到的Stefan Steinegger(我感谢Gristy的努力和时间),我的方法都不返回Obj4,我发现了一个问题,决定实施完全不同的方法。现在,我的KeyAndValue类还有一个int散列字段,当一个构造函数被称为Hash字段时,该字段由
key.GetHashCode()^tag.GetHashCode()
填充。它简化了比较,因为现在我首先将list1与list2组合起来,然后通过以下方式发送:CombinedList.GroupBy(x=>x.Hash)代码>结果似乎是正确的:)您的两个方法都不会返回obj4
。您正在寻找Union
?1:是的,我正在将结果保存到列表中2:您的KeyComparer没有返回具有相同键但不同标记的对象3:我不确定dictionary在这里是否有效,因为我提到KeyAndValue对象包含两个以上的字段,所以我可以创建dictionary该键具有什么数据类型?我的意思是Dictionary
通过键快速查找对象。键是一个字符串字段,标记是一个带有字符串字段名的标记(另一个类)对象类型的字段。现在回想起来,也许前面的方法一开始就不起作用,因为我比较了返回标记类对象的标记字段,而不是od tag.name.wird。我还是不明白你想要什么。处理哈希代码时要小心。它们不能取代真正的比较。散列只是一种性能改进,以避免在散列已经不同时调用昂贵的Equals
。然而,相等的散列并不意味着相等的值!相等散列表示必须调用Equals
。按哈希代码分组看起来很奇怪GroupBy
还应该能够使用比较器。
class KeyComparer : IEqualityComparer<KeyAndValue>
{
public bool Equals(KeyAndValue x, KeyAndValue y)
{
if (ReferenceEquals(x, y))
return true;
if (ReferenceEquals(x, null) || ReferenceEquals(y, null))
return false;
return x.key == y.key;
}
public int GetHashCode(KeyAndValue keyAndValue)
{
if (ReferenceEquals(keyAndValue, null))
return 0;
return keyAndValue.key == null ? 0 : keyAndValue.key.GetHashCode();
}
}