为什么Enumerable.SequenceEqual将其比较器视为IEqualityComparer?该算法似乎没有使用GetHashCode。为什么不采用Func<TSource, TSource, bool>
谓词,类似于First采用Func<TSource, bool>
的方式?
答案 0 :(得分:1)
我很想说“因为”。
如果您查看其他类似方法(例如Enumerable.Distinct),他们也会在重载中使用IEqualityComparer
。
此外,IEqualityComparer
是检查对象是否相等的“正确”方法。 Func<TSource, TSource, bool>
不会检查是否相等,它会在此时检查对象是否足够类似于您的特定用途。
幸运的是,制作自己的扩展方法很容易。例如,MoreLinq有DistinctBy
的实现,您可以查看。
答案 1 :(得分:1)
现在.NET Core是开源的,我在GitHub上将此问题发布为issue。希望,这将转化为答案或改进。
更新 - 从GitHub问题中获取有关现有设计及其问题的可能理由的详细信息:
IEqualityComparer
,尽管它的名字,确实做了两件事:哈希 并检查是否平等。 a之间唯一的行为差异Func<TSource, TSource, bool>
和IEqualityComparer
就是这样IEqualityComparer
有GetHashCode
方法。如果你想做的一切 检查序列是否相等,你需要IEqualityComparer
尽管如此,写下散列代码(这可能很难做得很好) 它可能永远不会被使用(但你不能指望它永远不会被使用 使用是因为SequenceEqual
没有记录它不会使用它。通常,您与
SequenceEqual
进行比较的类型会碰巧 一个或多个IEqualityComparer
个伴随类型,以便它们可以 存储在散列容器中。也许这就是为什么IEqualityComparer
被选为参数。但是,也有很多次 当没有IEqualityComparer
并且没有散列时 需求。在这些情况下,必须创建一个类并实现GetHashCode
是浪费。
答案 2 :(得分:0)
我并没有真正回答你的问题,但这里有重载:
public static bool SequenceEqual<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second,
Func<TSource, TSource, bool> predicate)
{
return first.SequenceEqual(second, new PredicateEqualityComparer<TSource>(predicate));
}
public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, Func<TKey, TKey, bool> predicate)
{
return outer.Join(inner, outerKeySelector, innerKeySelector, resultSelector, new PredicateEqualityComparer<TKey>(predicate));
}
public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer,
IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector,
Func<TOuter, IEnumerable<TInner>, TResult> resultSelector, Func<TKey, TKey, bool> predicate)
{
return outer.GroupJoin(inner, outerKeySelector, innerKeySelector, resultSelector,
new PredicateEqualityComparer<TKey>(predicate));
}
public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector, Func<TKey, TKey, bool> predicate)
{
return source.GroupBy(keySelector, new PredicateEqualityComparer<TKey>(predicate));
}
public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(
this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, TKey, bool> predicate)
{
return source.GroupBy(keySelector, elementSelector, new PredicateEqualityComparer<TKey>(predicate));
}
public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector, Func<TKey, IEnumerable<TSource>, TResult> resultSelector,
Func<TKey, TKey, bool> predicate)
{
return source.GroupBy(keySelector, resultSelector, new PredicateEqualityComparer<TKey>(predicate));
}
public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector,
Func<TKey, IEnumerable<TElement>, TResult> resultSelector, Func<TKey, TKey, bool> predicate)
{
return source.GroupBy(keySelector, elementSelector, resultSelector, new PredicateEqualityComparer<TKey>(predicate));
}
public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source,
Func<TSource, TSource, bool> predicate)
{
return source.Distinct(new PredicateEqualityComparer<TSource>(predicate));
}
public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, Func<TSource, TSource, bool> predicate)
{
return first.Union(second, new PredicateEqualityComparer<TSource>(predicate));
}
public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first,
IEnumerable<TSource> second, Func<TSource, TSource, bool> predicate)
{
return first.Intersect(second, new PredicateEqualityComparer<TSource>(predicate));
}
public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second,
Func<TSource, TSource, bool> predicate)
{
return first.Except(second, new PredicateEqualityComparer<TSource>(predicate));
}
public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector, Func<TKey, TKey, bool> predicate)
{
return source.ToDictionary(keySelector, new PredicateEqualityComparer<TKey>(predicate));
}
public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, TKey, bool> predicate)
{
return source.ToDictionary(keySelector, elementSelector, new PredicateEqualityComparer<TKey>(predicate));
}
public static ILookup<TKey, TSource> ToLookup<TSource, TKey>(this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector, Func<TKey, TKey, bool> predicate)
{
return source.ToLookup(keySelector, new PredicateEqualityComparer<TKey>(predicate));
}
public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value,
Func<TSource, TSource, bool> predicate)
{
return source.Contains(value, new PredicateEqualityComparer<TSource>(predicate));
}
实现了这个目标:
public class PredicateEqualityComparer<T> : IEqualityComparer<T>
{
private Func<T, T, bool> _predicate;
public PredicateEqualityComparer(Func<T, T, bool> predicate)
{
_predicate = predicate;
}
public bool Equals(T a, T b)
{
return _predicate(a, b);
}
public int GetHashCode(T a)
{
return a.GetHashCode();
}
}
我只测试了SequenceEqual。也许有些超载因为散列而无法按预期工作。这取决于你,想一想。