让我们先回顾一下MoreLinq
API,下面是代码DistinctBy
:
MoreLinq - DistinctBy
源代码
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
return _(); IEnumerable<TSource> _()
{
var knownKeys = new HashSet<TKey>(comparer);
foreach (var element in source)
{
if (knownKeys.Add(keySelector(element)))
yield return element;
}
}
}
在职的
- 在内部使用
HashSet<T>
它只检查第一个匹配项并返回与T
Key 匹配的 Type 的第一个元素,其余的都被忽略,因为 Key 已经添加到 HashSet
- 获取与集合中每个唯一 Keyin 相关的第一个元素的最简单方法,如
Func<TSource, TKey> keySelector
- 用例是有限的(GroupBy 可以实现的子集,也可以从您的代码中明确)
可枚举 - GroupBy
(源代码)
public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector) {
return new GroupedEnumerable<TSource, TKey, TElement>(source, keySelector, elementSelector, null);
}
internal class GroupedEnumerable<TSource, TKey, TElement> : IEnumerable<IGrouping<TKey, TElement>>
{
IEnumerable<TSource> source;
Func<TSource, TKey> keySelector;
Func<TSource, TElement> elementSelector;
IEqualityComparer<TKey> comparer;
public GroupedEnumerable(IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer) {
if (source == null) throw Error.ArgumentNull("source");
if (keySelector == null) throw Error.ArgumentNull("keySelector");
if (elementSelector == null) throw Error.ArgumentNull("elementSelector");
this.source = source;
this.keySelector = keySelector;
this.elementSelector = elementSelector;
this.comparer = comparer;
}
public IEnumerator<IGrouping<TKey, TElement>> GetEnumerator() {
return Lookup<TKey, TElement>.Create<TSource>(source, keySelector, elementSelector, comparer).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}
在职的
- 可以看出,内部使用
LookUp
数据结构对给定 Key 的所有数据进行分组
- 通过投影为元素和结果选择提供灵活性,因此能够满足许多不同的用例
概括
MoreLinq - DistinctBy
实现了可以实现的一小部分Enumerable - GroupBy
。如果您的用例是特定的,请使用更多 Linq API
- 对于您的用例,由于范围有限,速度明智
MoreLinq - DistinctBy
会更快,因为与 不同Enumerable - GroupBy
,DistinctBy
不会首先聚合所有数据然后为每个唯一键先选择,MoreLinq API 只会忽略第一条记录之外的数据
- 如果要求是特定的用例并且不需要数据投影,那么
MoreLinq
是更好的选择。
这是 Linq 中的一个经典案例,其中多个 API 可以提供相同的结果,但我们需要警惕成本因素,因为GroupBy
这里的任务比您期望的要广泛得多DistinctBy