如何通过保留 IGroupings 来过滤 IGrouping 的 IEnumerable 的元素

Mar*_*tin 2 c# linq

我有一个IGroupings序列

IEnumerable<IGrouping<Key, Element>> sequence = ...;
Run Code Online (Sandbox Code Playgroud)

和一个谓词

Func<Element, bool> predicate = ...;
Run Code Online (Sandbox Code Playgroud)

如何Element通过保持结果 an来过滤sIEnumerable<IGrouping<Key, Element>>而不使序列变平并重新创建完全重新创建分组?

我可以做类似的事情

IEnumerable<IGrouping<Key, Element>> filtered =
    from grouping in sequence
    from element in grouping
    where predicate(element)
    select new { grouping.Key, element } into keyElem
    group keyElem.element by keyElem.Key into g
    select g;
Run Code Online (Sandbox Code Playgroud)

但是,根据序列的大小和所涉及的类型,这需要一些时间和/或内存。

我想“简单地”过滤IGroupings 中的元素。我会在结果中接受空分组。

(我认为这个问题可以通过回答 how to filter the elements of anIEnumerable<IEnumerable<Element>>同时保持结果 an的问题来回答IEnumerable<IEnumerable<Element>>。)

Jon*_*eet 5

您不能修改现有的IGrouping,但您可以轻松创建自己的实现和辅助方法:

public static class Groupings
{
    public static IGrouping<TKey, TElement>
        FilterElements<TKey, TElement>(
        this IGrouping<TKey, TElement> grouping,
        Func<TElement, bool> predicate) =>
        new LateGrouping<TKey, TElement>(grouping.Key, grouping.Where(predicate));
}

internal class LateGrouping<TKey, TElement> : IGrouping<TKey, TElement>
{
    public TKey Key { get; }
    private readonly IEnumerable<TElement> elements;

    public LateGrouping(TKey key, IEnumerable<TElement> elements)
    {
        Key = key;
        this.elements = elements;
    }

    public IEnumerator<TElement> GetEnumerator() => elements.GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
Run Code Online (Sandbox Code Playgroud)

然后你就可以拿你的IEnumerable<IGrouping<...>>并使用一个普通的选择,在里面过滤:

groupings = groupings.Select(g => g.FilterElements(predicate));
Run Code Online (Sandbox Code Playgroud)