“一个用于嵌套的 IGroupings 的类似 SelectMany 的扩展方法”

huangapple go评论68阅读模式
英文:

A SelectMany-like extension method for nested IGroupings

问题

Here is the translated content:

假设我有一个可枚举对象,我已经两次应用了.GroupBy(),以获得嵌套的IGrouping

IEnumerable<IGrouping<TOuterKey, IGrouping<TInnerKey, TElement>>> source = enumerable.GroupBy(o => o.InnerKey).GroupBy(g => g.OuterKey);

对于嵌套的IEnumerable,只需应用.SelectMany()即可获得扁平化的IEnumerable,其中包含所有结果。但是,对于IGrouping,情况并不那么简单。假设我想要创建一个通用的扩展方法来执行此操作:

public static IEnumerable<IGrouping<TResultKey, TResultElement>> SelectMany<TOuterKey, TInnerKey, TInputElement, TResultKey, TResultElement>(
    this IEnumerable<IGrouping<TOuterKey, IGrouping<TInnerKey, TInputElement>>> source,
    Func<IGrouping<TOuterKey, IGrouping<TInnerKey, TInputElement>>, TResultKey> keySelector,
    Func<TOuterKey, TInnerKey, TInputElement, TResultElement> valueSelector)

如何创建这个方法?

英文:

Suppose that I have an enumerable on which I have applied .GroupBy() twice to end up with nested IGroupings:

IEnumerable<IGrouping<TOuterKey, IGrouping<TInnerKey, TElement>>> source = enumerable.GroupBy(o => o.InnerKey).GroupBy(g => g.OuterKey);

For nested IEnumerables, it is easy to just apply .SelectMany() to get a flattened IEnumerable with all of the results. For IGroupings, however, this is not so simple. Suppose I wanted a generalised extension method to do this:

public static IEnumerable<IGrouping<TResultKey, TResultElement>> SelectMany<TOuterKey, TInnerKey, TInputElement, TResultKey, TResultElement>(
    this IEnumerable<IGrouping<TOuterKey, IGrouping<TInnerKey, TInputElement>>> source,
    Func<IGrouping<TOuterKey, IGrouping<TInnerKey, TInputElement>>, TResultKey> keySelector,
    Func<TOuterKey, TInnerKey, TInputElement, TResultElement> valueSelector)

How would I create that?

答案1

得分: 0

I left some time between posting the question and the answer, to give anyone wanting to give this a try a chance, but now I'll give you my answer:

我在发布问题和答案之间留了一些时间,以给任何想尝试的人一个机会,但现在我会给你我的答案:

public static IEnumerable<IGrouping<TResultKey, TResultElement>> GroupSelectMany<TOuterKey, TInnerKey, TSourceElement, TResultKey, TResultElement>(
    this IEnumerable<IGrouping<TOuterKey, IGrouping<TInnerKey, TSourceElement>>> source,
    Func<IGrouping<TOuterKey, IGrouping<TInnerKey, TSourceElement>>, TResultKey> keySelector,
    Func<TOuterKey, TInnerKey, TSourceElement, TResultElement> elementSelector)
{
    elementSelector = elementSelector ?? ((outerKey, innerKey, element) => (TResultElement)(object)element);

    return source.SelectMany(
        gg => new IGrouping<TResultKey, TResultElement>[]
        {
            new Grouping<TResultKey, TResultElement>(
                keySelector(gg),
                gg.SelectMany(
                    g => g.Select(
                        o => elementSelector(gg.Key, g.Key, o))))
        }); 
}

You will also need an implementation of IGrouping, which I have found here, but which I am only including as private for encapsulation purposes:

你还需要一个IGrouping的实现,我在这里找到了,但我只包含为private以实现封装目的的部分:

private class Grouping<TKey, TElement> : List<TElement>, IGrouping<TKey, TElement>
{
    public Grouping(TKey key) : base() => Key = key;
    public Grouping(TKey key, int capacity) : base(capacity) => Key = key;
    public Grouping(TKey key, IEnumerable<TElement> collection)
        : base(collection) => Key = key;
    public TKey Key { get; }
}
英文:

I left some time between posting the question and the answer, to give anyone wanting to give this a try a chance, but now I'll give you my answer:

public static IEnumerable&lt;IGrouping&lt;TResultKey, TResultElement&gt;&gt; GroupSelectMany&lt;TOuterKey, TInnerKey, TSourceElement, TResultKey, TResultElement&gt;(
    this IEnumerable&lt;IGrouping&lt;TOuterKey, IGrouping&lt;TInnerKey, TSourceElement&gt;&gt;&gt; source,
    Func&lt;IGrouping&lt;TOuterKey, IGrouping&lt;TInnerKey, TSourceElement&gt;&gt;, TResultKey&gt; keySelector,
    Func&lt;TOuterKey, TInnerKey, TSourceElement, TResultElement&gt; elementSelector)
{
    elementSelector = elementSelector ?? ((outerKey, innerKey, element) =&gt; (TResultElement)(object)element);
    
    return source.SelectMany(
        gg =&gt; new IGrouping&lt;TResultKey, TResultElement&gt;[]
        {
            new Grouping&lt;TResultKey, TResultElement&gt;(
                keySelector(gg),
                gg.SelectMany(
                    g =&gt; g.Select(
                        o =&gt; elementSelector(gg.Key, g.Key, o))))
        }); 
}

You will also need an implementation of IGrouping, which I have found here, but which I am only including as private for encapsulation purposes:

private class Grouping&lt;TKey, TElement&gt; : List&lt;TElement&gt;, IGrouping&lt;TKey, TElement&gt;
{
    public Grouping(TKey key) : base() =&gt; Key = key;
    public Grouping(TKey key, int capacity) : base(capacity) =&gt; Key = key;
    public Grouping(TKey key, IEnumerable&lt;TElement&gt; collection)
        : base(collection) =&gt; Key = key;
    public TKey Key { get; }
}

huangapple
  • 本文由 发表于 2023年8月5日 03:19:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76838652.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定