繁体   English   中英

MoreLINQ的DistinctBy和Linq的GroupBy有什么区别

[英]What is the difference between MoreLINQ's DistinctBy and Linq's GroupBy

我有两个版本的按项目列表分组

List<m_addtlallowsetup> xlist_distincted = xlist_addtlallowsetups.DistinctBy(p => new { p.setupcode, p.allowcode }).OrderBy(y => y.setupcode).ThenBy(z => z.allowcode).ToList();

和groupby

List <m_addtlallowsetup>  grouped = xlist_addtlallowsetups.GroupBy(p => new { p.setupcode, p.allowcode }).Select(grp => grp.First()).OrderBy(y => y.setupcode).ThenBy(z => z.allowcode).ToList();

在我看来,这两者是相同的,但必须由外行对其差异,性能和劣势进行解释

首先,让我们回顾一下MoreLinq API,以下是DistinctBy的代码:

MoreLinq-与众不同

源代码

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>它只是检查第一个匹配项并返回与Key相匹配的Type T的第一个元素,其余的都将被忽略,因为Key已经添加到HashSet中了
  • 获得与Func<TSource, TKey> keySelector定义的集合中每个唯一Keyin有关的第一个元素的最简单方法
  • 用例是有限的(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的所有数据分组
  • 通过投影为元素和结果选择提供灵活性,从而能够满足许多不同的用例

摘要

  1. MoreLinq - DistinctBy实现了Enumerable - GroupBy可以实现的一小部分。 如果您的用例是特定的,请使用More Linq API
  2. 对于您的用例,速度是明智的,因为范围受到限制MoreLinq - DistinctBy会更快,因为与Enumerable - GroupBy不同, DistinctBy不会先汇总所有数据,然后为每个唯一的键首先选择,MoreLinq API只会忽略第一条记录以外的数据
  3. 如果需求是特定的用例,并且不需要数据投影,则MoreLinq是更好的选择。

这是Linq中的经典案例,其中多个API可以提供相同的结果,但是我们需要警惕成本因素,因为此处的GroupBy设计用于比DistinctBy期望的任务更广泛的任务

差异

GroupBy应该会产生一个包含关键字(分组条件)及其值的“组”。 这就是为什么您需要首先执行Select(grp => grp.First())

您可能会怀疑MoreLinq只是它的简写。 通过来源了解更多信息DistinctBy实际上是通过选择HashSet每个新项在内存中完成的。 HashSet#Add将添加item,如果它是HashSet的新元素,则返回true,然后yield将新添加的元素返回到可枚举中。

哪一个?

SQL相关

基于以上差异,您可以说GroupBy然后用Select进行投影是更安全的方法,因为如果使用的是Entity Framework(或者我想是Linq2Sql),它可以转换为SQL命令。 能够转换为SQL命令是一个很大的优势,它可以减轻应用程序的负担并将代理操作委派给数据库服务器。

但是,您必须了解,实体框架中的GroupBy实际上使用了被视为复杂操作的OUTER JOIN ,在某些情况下,它可能会导致您的查询立即被删除。 这是非常罕见的情况,即使我抛出的查询也有很多列,使用了大约四个GroupBy ,一堆排序和Where

反对对象

粗略地说,当处理一个已经存在于内存中的枚举数时。 然后运行GroupBy Select可能最终需要两次操作来迭代您的枚举。 直接使用MoreLinq的DistinctBy可以节省一些时间,因为它保证是由HashSet支持的单个操作,正如Mrinal Kamboj回答所解释的,并针对源代码进行了深入分析。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM