Sum hierarchical data using LINQ?

Is it possible to summarize hierarchical data using .NET LINQ?

My data class is as follows:

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

So, I would like some data to look like this, but the tree could, of course, be arbitrarily deep.

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

Is it possible to sum all the amounts and get the result 60 with one simple LINQ query?

+4
source share
2 answers

Technically, you can write recursive lambda expressions , but you need to be insane or insanely bright to try (I didn't understand which ones). But you can fool:

  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); 
+2
source

You can do this with a higher order function:

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

Please note that if you can guarantee that node. Children will never be empty, summer can be easier:

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

Alternatively, you can use the null coalescing operator:

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

Of course, you can put this in a separate method:

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

Note that the ugliness here is due to the ambiguity in transforming groups of methods. Method groups are not very fond of output type.

and then call SumNodes(amount) . Lots of options :)

Full example of the first form:

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

I'm not sure what I would call any of these "simple" LINQ queries, mind you ...

+15
source

Source: https://habr.com/ru/post/1285950/


All Articles