Somme des données hiérarchiques LINQ?
-
13-09-2019 - |
Question
Est-il possible de résumer des données hiérarchiques LINQ de .NET?
Ma classe de données ressemble à ceci:
class Node
{
public decimal Amount;
public IEnumerable<Node> Children { get; set; }
}
J'aurais certaines données ressemble à cela, mais l'arbre pourrait bien sûr être arbitrairement profond.
var amounts = new Node
{
Amount = 10;
Children = new[]
{
new Node
{
Amount = 20
},
new Node
{
Amount = 30
}
}
};
Il est possible somme tous les montants et obtenir le résultat 60 avec une simple requête LINQ?
La solution
pouvez écrire des expressions lambda récursives , mais vous devez être fou ou incroyablement lumineux pour essayer (je ne l'ai pas compris que). Mais vous pouvez tricher:
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);
Autres conseils
Vous pouvez le faire avec une fonction d'ordre supérieur:
Func<Node, decimal> summer = null;
summer = node => node.Amount +
(node.Children == null ? 0m : node.Children.Sum(summer));
decimal total = summer(amounts);
Notez que si vous pouvez vous assurer que node.Children ne sera jamais nulle, l'été peut être plus simple:
summer = node => node.Amount + node.Children.Sum(summer);
Vous pouvez utiliser l'opérateur coalescent null:
summer = node => node.Amount +
(node.Children ?? Enumerable.Empty<Node>()).Sum(summer);
Bien sûr, vous pouvez mettre cela en une méthode distincte au lieu:
static decimal SumNodes(Node node)
{
return node.Amount +
(node.Children ?? Enumerable.Empty<Node>())
.Sum((Func<Node, decimal>)SumNodes);
}
Notez la laideur ici est due à une ambiguïté dans les conversions de groupe de méthode. groupes de méthode ne reçoivent pas beaucoup d'amour dans l'inférence de type.
puis appelez SumNodes(amount)
. Beaucoup d'options:)
Exemple complet de la première forme:
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);
}
}
Je ne suis pas sûr que je dirais l'un de ces un « simple » requête LINQ, l'esprit que vous ...