英文:
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<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:
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; }
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论