GroupBy 中的内存节省

发布于 2024-11-08 23:39:10 字数 174 浏览 0 评论 0原文

对许多项目(GB)运行 LINQ to Objects GroupBy() 方法可能会消耗内存。如果 IEnumerable 已经按键排序,我们可以编写一个不消耗太多内存的 GroupBy

我在哪里可以找到具有这种方法的库?

Running LINQ to Objects GroupBy() method for many items (gigabytes) can be memory consuming. If the IEnumerable<T> is already ordered by the key, we could write an GroupBy that didn't consume as much memory.

Where can I find a library that has such method?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

┈┾☆殇 2024-11-15 23:39:10

框架中没有任何东西可以做到这一点。如果您不需要实际的 IGrouping<,> 您可以使用此:

static IEnumerable<IList<TElement>> GroupByChanges<TElement, TKey>
    (this IEnumerable<TElement> source,
     Func<TElement, TKey> projection)
{
    // TODO: Argument validation, splitting this into two methods
    // to achieve eager validation.
    // TODO: Allow a custom comparer to be used, possibly even
    // an IComparer<T> instead of an IEqualityComparer<T>
    IEqualityComparer<TKey> comparer = EqualityComparer<TKey>.Default;

    using (IEnumerator<TElement> iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
        {
            yield break;
        }
        TKey currentKey = projection(iterator.Current);
        IList<TElement> currentList = new List<TElement> { iterator.Current };
        while (iterator.MoveNext())
        {
            TKey key = projection(iterator.Current);
            if (!comparer.Equals(currentKey, key))
            {
                yield return currentList;
                currentList = new List<TElement>();
            }
            currentList.Add(iterator.Current);
        }
        yield return currentList;
    }
}

如果您需要完整的 IGrouping<,> 实现,则会稍微困难一些 -但您随时可以获取我的Edulinq 实现

GroupByChanges 的实现几乎不会改变 - 只需更改 currentList 赋值以将密钥传递给 Grouping 构造函数:

Grouping<TKey, TElement> currentGroup = new Grouping<TKey, TElement>(currentKey)
    { iterator.Current };

There's nothing in the framework to do this. If you don't need an actual IGrouping<,> you could use this:

static IEnumerable<IList<TElement>> GroupByChanges<TElement, TKey>
    (this IEnumerable<TElement> source,
     Func<TElement, TKey> projection)
{
    // TODO: Argument validation, splitting this into two methods
    // to achieve eager validation.
    // TODO: Allow a custom comparer to be used, possibly even
    // an IComparer<T> instead of an IEqualityComparer<T>
    IEqualityComparer<TKey> comparer = EqualityComparer<TKey>.Default;

    using (IEnumerator<TElement> iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
        {
            yield break;
        }
        TKey currentKey = projection(iterator.Current);
        IList<TElement> currentList = new List<TElement> { iterator.Current };
        while (iterator.MoveNext())
        {
            TKey key = projection(iterator.Current);
            if (!comparer.Equals(currentKey, key))
            {
                yield return currentList;
                currentList = new List<TElement>();
            }
            currentList.Add(iterator.Current);
        }
        yield return currentList;
    }
}

If you need a full IGrouping<,> implementation it'll be slightly harder - but you could always grab my Edulinq implementation.

The implementation of GroupByChanges would change very little - just change the currentList assignments to pass in the key to the Grouping constructor:

Grouping<TKey, TElement> currentGroup = new Grouping<TKey, TElement>(currentKey)
    { iterator.Current };
暮年慕年 2024-11-15 23:39:10

你的问题很具体。您不太可能找到已经做到这一点的库。如果您的项目是按您用于分组的键排序的,那么您自己对该列表进行“分组”是一项近乎微不足道的任务。

Your problem is very specific. It is highly unlikely that you will find a library that already does this. If your items are ordered by the key which you use to group, it is a near-trivial task to 'group' this list yourself.

鸠书 2024-11-15 23:39:10

您可以轻松地自己实现它:

public static class Extensions
{

    public static IEnumerable<IGrouping<TKey, TSource>> GroupByAlreadyOrdered<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
    {
        return source.GroupByAlreadyOrdered(keySelector, null);
    }

    public static IEnumerable<IGrouping<TKey, TSource>> GroupByAlreadyOrdered<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
    {
        TKey currentKey = default(TKey);
        bool first = true;
        List<TSource> currentGroup = null;
        comparer = comparer ?? EqualityComparer<TKey>.Default;

        foreach (var item in source)
        {
            TKey key = keySelector(item);
            if (first || !comparer.Equals(key, currentKey))
            {
                if (currentGroup != null && currentGroup.Any())
                {
                    yield return new Grouping<TKey, TSource>(currentKey, currentGroup);
                }
                currentGroup = new List<TSource>();
            }

            currentGroup.Add(item);
            first = false;
            currentKey = key;
        }
        // Last group
        if (currentGroup != null && currentGroup.Any())
        {
            yield return new Grouping<TKey, TSource>(currentKey, currentGroup);
        }
    }

    private class Grouping<TKey, TElement> : IGrouping<TKey, TElement>
    {
        private readonly TKey _key;
        private readonly IEnumerable<TElement> _elements;

        public Grouping(TKey key, IEnumerable<TElement> elements)
        {
            _key = key;
            _elements = elements;
        }

        public TKey Key
        {
            get { return _key; }
        }

        public IEnumerator<TElement> GetEnumerator()
        {
            return _elements.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

}

You could easily implement it yourself:

public static class Extensions
{

    public static IEnumerable<IGrouping<TKey, TSource>> GroupByAlreadyOrdered<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
    {
        return source.GroupByAlreadyOrdered(keySelector, null);
    }

    public static IEnumerable<IGrouping<TKey, TSource>> GroupByAlreadyOrdered<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
    {
        TKey currentKey = default(TKey);
        bool first = true;
        List<TSource> currentGroup = null;
        comparer = comparer ?? EqualityComparer<TKey>.Default;

        foreach (var item in source)
        {
            TKey key = keySelector(item);
            if (first || !comparer.Equals(key, currentKey))
            {
                if (currentGroup != null && currentGroup.Any())
                {
                    yield return new Grouping<TKey, TSource>(currentKey, currentGroup);
                }
                currentGroup = new List<TSource>();
            }

            currentGroup.Add(item);
            first = false;
            currentKey = key;
        }
        // Last group
        if (currentGroup != null && currentGroup.Any())
        {
            yield return new Grouping<TKey, TSource>(currentKey, currentGroup);
        }
    }

    private class Grouping<TKey, TElement> : IGrouping<TKey, TElement>
    {
        private readonly TKey _key;
        private readonly IEnumerable<TElement> _elements;

        public Grouping(TKey key, IEnumerable<TElement> elements)
        {
            _key = key;
            _elements = elements;
        }

        public TKey Key
        {
            get { return _key; }
        }

        public IEnumerator<TElement> GetEnumerator()
        {
            return _elements.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

}
风吹短裙飘 2024-11-15 23:39:10

和托马斯一样,但速度稍快一些

public static IEnumerable<IGrouping<TKey, TSource>> FastGroupBy<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector)
{
    using (var enumerator = source.GetEnumerator())
    {
        if (enumerator.MoveNext())
        {
            Grouping<TKey, TSource> grouping;
            List<TSource> list = new List<TSource>();
            TKey key = keySelector(enumerator.Current);
            list.Add(enumerator.Current);
            while (enumerator.MoveNext())
            {
                var currentKey = keySelector(enumerator.Current);
                if (key.Equals(currentKey))
                {
                    list.Add(enumerator.Current);
                    continue;
                }

                grouping = new Grouping<TKey, TSource>(key, list);
                yield return grouping;

                key = currentKey;
                list = new List<TSource>();
                list.Add(enumerator.Current);
            }

            grouping = new Grouping<TKey, TSource>(key, list);
            yield return grouping;
        }
    }
}

Like Thomas' but slightly faster

public static IEnumerable<IGrouping<TKey, TSource>> FastGroupBy<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector)
{
    using (var enumerator = source.GetEnumerator())
    {
        if (enumerator.MoveNext())
        {
            Grouping<TKey, TSource> grouping;
            List<TSource> list = new List<TSource>();
            TKey key = keySelector(enumerator.Current);
            list.Add(enumerator.Current);
            while (enumerator.MoveNext())
            {
                var currentKey = keySelector(enumerator.Current);
                if (key.Equals(currentKey))
                {
                    list.Add(enumerator.Current);
                    continue;
                }

                grouping = new Grouping<TKey, TSource>(key, list);
                yield return grouping;

                key = currentKey;
                list = new List<TSource>();
                list.Add(enumerator.Current);
            }

            grouping = new Grouping<TKey, TSource>(key, list);
            yield return grouping;
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文