使用删除递归对数据进行分层分组
本文关键字:分层 数据 删除 递归 | 更新日期: 2023-09-27 18:36:13
我在这个堆栈溢出中找到了分层分组的好解决方案。
如何使用 LINQ 对数据进行分层分组?
它对我帮助很大,但我想问一下我如何才能达到相同的结果,但没有递归。老实说,我在转换它时遇到了问题,因为递归对我来说是自然的方法。任何人都可以将此方法转换为不使用递归?
用法:
var result = customers.GroupByMany(c => c.Country, c => c.City);
编辑:
public class GroupResult
{
public object Key { get; set; }
public int Count { get; set; }
public IEnumerable<GroupResult> SubGroups { get; set; }
public override string ToString()
{ return string.Format("{0} ({1})", Key, Count); }
}
public static class MyEnumerableExtensions
{
public static IEnumerable<GroupResult> GroupByMany<TElement>(
this IEnumerable<TElement> elements,
params Func<TElement, object>[] groupSelectors)
{
if (groupSelectors.Length > 0)
{
var selector = groupSelectors.First();
//reduce the list recursively until zero
var nextSelectors = groupSelectors.Skip(1).ToArray();
return
elements.GroupBy(selector).Select(
g => new GroupResult
{
Key = g.Key,
Count = g.Count(),
SubGroups = g.GroupByMany(nextSelectors)
});
}
return null;
}
}
提前致谢
有点挑战性,但你来了:
public class GroupResult<T>
{
public object Key { get; set; }
public int Count { get; set; }
public IEnumerable<T> Items { get; set; }
public IEnumerable<GroupResult<T>> SubGroups { get; set; }
public override string ToString() { return string.Format("{0} ({1})", Key, Count); }
}
public static class MyEnumerableExtensions
{
public static IEnumerable<GroupResult<TElement>> GroupByMany<TElement>(
this IEnumerable<TElement> elements,
params Func<TElement, object>[] groupSelectors)
{
Func<IEnumerable<TElement>, IEnumerable<GroupResult<TElement>>> groupBy = source => null;
for (int i = groupSelectors.Length - 1; i >= 0; i--)
{
var keySelector = groupSelectors[i]; // Capture
var subGroupsSelector = groupBy; // Capture
groupBy = source => source.GroupBy(keySelector).Select(g => new GroupResult<TElement>
{
Key = g.Key,
Count = g.Count(),
Items = g,
SubGroups = subGroupsSelector(g)
});
}
return groupBy(elements);
}
}
诀窍是以相反的顺序构建分组 lambda 表达式,使用上一步的结果并使用闭包来捕获执行 lambda 所需的必要信息。
主要问题应该是为什么要从实现中摆脱递归?您提供的代码具有最大递归深度 = groupSelectors.Length。在这种情况下,我认为堆栈使用不应该是您关心的问题。
Ivan 提供的解决方案是正确的,但我认为它也具有间接递归方法,并提供相同的堆栈消耗级别。它不是命名声明的方法调用,而是构建嵌套委托 (Func) 调用链。
如果您的目标是欺骗一些静态代码分析工具(他们通常不喜欢递归调用),则可以将 GroupByMany 的一部分提取到单独的方法中,然后从另一个方法调用一个。