当前位置: 代码迷 >> 综合 >> ToLookup 和 GroupBy 到底有什么不同?
  详细解决方案

ToLookup 和 GroupBy 到底有什么不同?

热度:15   发布时间:2024-01-12 08:04:27.0

咨询区

  • Shlomo

.ToLookup<TSource, TKey> 返回的是 ILookup<TKey, TSource>, 但我发现 ILookup<TKey, TSource>  同时也实现了 IEnumerable<IGrouping<TKey, TSource>> 接口。

.GroupBy<TSource, TKey> 直接返回的是 IEnumerable<IGrouping<Tkey, TSource>> 接口。

ILookup 有一个方便的属性索引器,所以它具有像字典一样的行为,但 GroupBy 却不能,所以用起来很痛苦,唯一的方式就是通过 foreach 对其进行迭代,换句话说,GroupBy 能做的,貌似 ToLookup 都能很好的完成。

总之,给我的疑惑就是,有了 ToLookup() 是不是 GroupBy() 就没用武之地了?

回答区

  • Allon Guralnek

这两者是类似的,但它们的应用场景完全不一样, .ToLookup() 方法返回的是所有已经分好组的可立即使用的对象,简而言之就是 立即加载, 可参考其源码:

public static ILookup<TKey, TSource> ToLookup<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{return Lookup<TKey, TSource>.Create(source, keySelector, IdentityFunction<TSource>.Instance, null);
}internal static Lookup<TKey, TElement> Create<TSource>(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");}Lookup<TKey, TElement> lookup = new Lookup<TKey, TElement>(comparer);foreach (TSource item in source){lookup.GetGrouping(keySelector(item), create: true).Add(elementSelector(item));}return lookup;
}

可以看到,它里面已经执行了 foreach 操作。

.GroupBy() 它仅仅是构建了一个可迭代类,所以它是一个懒加载操作,参考如下源码:

public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{return new GroupedEnumerable<TSource, TKey, TSource>(source, keySelector, IdentityFunction<TSource>.Instance, null);
}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;
}

针对数据库的 Linq To Database 来说, GroupBy() 会被解析成 sql 中的 group by 关键词,所以它会在server端被执行而不是在客户端,因此如果你想在 group key 上做一些过滤条件,比如: (having),这是完全支持的,相关 Tolookup() 是将所有的数据加载到 client 内存中,然后在内存中做 groupby 操作,所以刚才说的附加过滤操作是无法支持的。

点评区

其实说的再多,一看源码就什么都知道了,所以说 ILSpy,Reflector,Dnspy 随身备着哈。