【问题标题】:Sum of hierarchical data using LINQ?使用 LINQ 的分层数据总和?
【发布时间】:2009-06-09 19:05:37
【问题描述】:

是否可以使用 .NET 的 LINQ 对分层数据求和?

我的数据类如下所示:

class Node
{
    public decimal Amount;
    public IEnumerable<Node> Children { get; set; }
}

所以我会让一些数据看起来像这样,但树当然可以任意深。

var amounts = new Node
{
    Amount = 10;
    Children = new[]
    {
        new Node
        {
            Amount = 20
        },
        new Node
        {
            Amount = 30
        }
    }
};

是否可以通过一个简单的 LINQ 查询将所有金额相加并得到结果 60?

【问题讨论】:

    标签: linq hierarchical-data


    【解决方案1】:

    你可以用高阶函数来做到这一点:

    Func<Node, decimal> summer = null;
    summer = node => node.Amount + 
                     (node.Children == null ? 0m : node.Children.Sum(summer));
    decimal total = summer(amounts);
    

    请注意,如果您可以确保 node.Children 永远不会为 null,那么 summer 可以更简单:

    summer = node => node.Amount + node.Children.Sum(summer);
    

    或者,您可以使用空合并运算符:

    summer = node => node.Amount + 
                     (node.Children ?? Enumerable.Empty<Node>()).Sum(summer);
    

    当然你可以把它放到一个单独的方法中:

    static decimal SumNodes(Node node)
    {
        return node.Amount + 
            (node.Children ?? Enumerable.Empty<Node>())
                .Sum((Func<Node, decimal>)SumNodes);
    }
    

    请注意,这里的丑陋是由于方法组转换中的模糊性。方法组在类型推断中不太受欢迎。

    然后拨打SumNodes(amount)。很多选择:)

    第一种形式的完整示例:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    class Node
    {
        public decimal Amount;
        public IEnumerable<Node> Children { get; set; }
    }
    
    public class Test
    {
        static void Main()
        {
            var amounts = new Node {
                Amount = 10, Children = new[] {
                    new Node { Amount = 20 },
                    new Node { Amount = 30 }
                }
            };
    
            Func<Node, decimal> summer = null;
            summer = node => node.Amount + 
                (node.Children == null ? 0m : node.Children.Sum(summer));
    
            decimal total = summer(amounts);
    
            Console.WriteLine(total);
        }
    }
    

    我不确定我是否会将这些称为“简单”LINQ 查询,请注意...

    【讨论】:

    • 严格来说,这更像是一个“高阶函数”,而不是真正的“递归 lambda”...
    • 我在尝试实现 SumNodes 函数时收到“模糊调用”错误。
    • 啊,是的,方法组调用异常。会修复的。
    • 最初,我开始将其编写为外部方法,并得到相同的方法组歧义 - 所以我使用 delegate=null 技巧进行了重构(与您的第一个方法相同)。
    【解决方案2】:

    从技术上讲,你可以write recursive lambda expressions,但你需要疯狂或疯狂才能尝试(我还没弄清楚哪个)。但你可以作弊:

        Func<Node, decimal> nodeSum = null;
        nodeSum = node => {
            decimal result = node.Amount;
            if (node.Children != null) {
                result = result + node.Children.Sum(nodeSum);
            }
            return result;
        };
        var value = nodeSum(amounts);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-05
      • 2010-11-07
      • 1970-01-01
      • 2016-06-26
      • 1970-01-01
      相关资源
      最近更新 更多