我想要一个自定义的相等比较器IEnumerable
。使用 @PaulZahra ' code,我创建了以下类:
class CustomEqualityComparer<T> : IEqualityComparer<IEnumerable<T>>
{
public bool Equals(IEnumerable<T> x, IEnumerable<T> y)
{
var enumerables = new Dictionary<T, uint>();
foreach (T item in x)
{
enumerables.Add(item, 1);
}
foreach (T item in y)
{
if (enumerables.ContainsKey(item))
{
enumerables[item]--;
}
else
{
return false;
}
}
return enumerables.Values.All(v => v == 0);
}
public int GetHashCode(IEnumerable<T> obj) => obj.GetHashCode();
}
问题是如果T
本身是IEnumerable
,那么ContainsKey
将检查引用相等性,而此相等比较器的点是检查值相等在任何给定的深度。
我想改为使用.Keys.Contains()
,因为它可以接受IEqualityComparer
作为参数:
if (enumerables.Keys.Contains(item, this)) // not sure if "this" or a new object
但是我收到以下错误( CS1929 ):
&#39; Dictionary.KeyCollection&#39;不包含&#39;包含&#39;的定义和最好的扩展方法重载&#39; Queryable.Contains(IQueryable,T,IEqualityComparer)&#39;需要一个类型为“IQueryable&#39;
的接收器
我不知道如何处理这个问题。怎么解决?感谢。
修改:请注意,此比较器并不关心订单。
答案 0 :(得分:2)
要拥有这样的递归比较器,如果Dictionary
是可枚举的,您只需要将适当的比较器传递给T
。我认为getting type T from IEnumerable<T>然后相当于new Dictionary<U, uint>(new CustomEqualityComparer<U>)
(使用Create instance of generic type?)应该达到你想要的效果。
注意:
GetHashCode
使用comparer,则必须提供与Equals
匹配的HashSet
的正确实现。序列的默认Equals
是与您的Equals
不对齐的引用比较。请注意,GetHashCode
的大多数实现取决于集合中项目的顺序 - 因此您需要找到适用于集合的项目。即每个项目的哈希码总和会做,可能会使分布略差。Distinct
这样的所有操作都已经采用了比较器。如果“设置相同”,您可以使用Distinct
- x.Distinct(y, comparerBuiltViaReflection)
while(count < 10){ count ++; yield return random.Next(); }
)时产生不同的结果, iteartion很重要(在每次迭代时重读大文件中的所有行)或者枚举可以表示无限序列(while(true){ yield return count++; }
)。答案 1 :(得分:1)
正如其他人所提到的,IEnumerable<T>
可以永远枚举,因此在该界面上执行此操作会很危险。我建议使用ICollection<T>
代替它 - 它有一个固定的大小。而且你会发现它适用于你想要使用的大多数类型。
此外,我建议使用TryGetValue
来减少查询字典所需的次数。
您的代码未正确保存第一个可枚举项中每个项目的数量。
GetHashCode需要考虑可枚举的每个成员。
所有这一切,这里是对您的实施的调整:
class CustomEqualityComparer<T> : IEqualityComparer<ICollection<T>>
{
public bool Equals(ICollection<T> x, ICollection<T> y)
{
if (x.Count != y.Count) return false;
var enumerables = new Dictionary<T, uint>(x.Count);
foreach (T item in x)
{
enumerables.TryGetValue(item, out var value);
enumerables[item] = value + 1;
}
foreach (T item in y)
{
var success = enumerables.TryGetValue(item, out var value);
if (success)
{
enumerables[item] = value - 1;
}
else
{
return false;
}
}
return enumerables.Values.All(v => v == 0);
}
public int GetHashCode(ICollection<T> obj)
{
unchecked
{
var hashCode = 0;
foreach(var item in obj)
{
hashCode += (item != null ? item.GetHashCode() : 0);
}
return hashCode;
}
}
}