2009-06-09 77 views
4

是否可以使用.NET的LINQ对分层数据进行求和?使用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 
     } 
    } 
}; 

这是可能的总和所有的金额,并得到60一个简单的LINQ查询结果?

回答

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); 
15

您可以用高阶函数做:

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

需要注意的是,如果你能保证node.Children永远不会为空,夏可简单了:

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查询,请注意...

+0

乔恩,我会再次赞赏这一次,但不会让我。 – 2009-06-09 10:05:20