C # Liste d'objets, comment obtenir la somme d'une propriété

158

J'ai une liste d'objets. Une propriété de l'entrée d'objet individuel est le montant. Comment obtenir la somme du montant?

Si ma liste était de type double, je pourrais peut-être faire quelque chose comme ceci:

double total = myList.Sum();

Cependant, je veux quelque chose de similaire, mais cette syntaxe est incorrecte.

double total = myList.amount.Sum();

Comment dois-je procéder pour y parvenir? J'adorerais utiliser la fonction Sum si possible au lieu de parcourir et de calculer la valeur.

Joseph U.
la source

Réponses:

310
using System.Linq;

...

double total = myList.Sum(item => item.Amount);
Alex LE
la source
12
Est-ce plus rapide que foreach par intérêt?
Coops
4
Je suis également intéressé par la question de @ CodeBlend. Ce calcul sera-t-il plus rapide qu'une boucle for?
rex
23
@Coops - Pour répondre à votre question ... en utilisant une liste contenant 100000 objets, chaque objet ayant une seule propriété de type de données double, la somme de la propriété 1000 fois en utilisant la solution ci-dessus (myList.Sum) prend 2,44 secondes contre 0,98 secondes avec foreach . Le temps écoulé est mesuré à l'aide de la classe Chronomètre pour la précision. Par conséquent, foreach est plus de 2x plus rapide que l'utilisation de myList.Sum.
Joe Gayetty du
36

Et si vous devez le faire sur des éléments qui correspondent à une condition spécifique ...

double total = myList.Where(item => item.Name == "Eggs").Sum(item => item.Amount);
Greg Quinn
la source
11

Une autre alternative:

myPlanetsList.Select(i => i.Moons).Sum();
utileBee
la source
5
Au lieu de .Select(i => i.Moons).Sum()vous pouvez utiliser.Sum(i => i.Moons)
Mason
1
@Mason, c'est vrai et c'est ainsi qu'Alex a abordé le problème dans sa réponse précédente, alors j'ai simplement proposé une manière différente de faire la même chose.
utileBee
1
Ah oui, désolé pour mon idée fausse.
Mason
J'apprécie que ce soit une réponse unique, mais les performances n'en souffriraient-elles pas?
Peter Lenjo le
2

Voici un exemple de code que vous pouvez exécuter pour effectuer un tel test:

var f = 10000000;
var p = new int[f];

for(int i = 0; i < f; ++i)
{
    p[i] = i % 2;
}

var time = DateTime.Now;
p.Sum();
Console.WriteLine(DateTime.Now - time);

int x = 0;
time = DateTime.Now;
foreach(var item in p){
   x += item;
}
Console.WriteLine(DateTime.Now - time);

x = 0;
time = DateTime.Now;
for(int i = 0, j = f; i < j; ++i){
   x += p[i];
}
Console.WriteLine(DateTime.Now - time);

Le même exemple pour un objet complexe est:

void Main()
{
    var f = 10000000;
    var p = new Test[f];

    for(int i = 0; i < f; ++i)
    {
        p[i] = new Test();
        p[i].Property = i % 2;
    }

    var time = DateTime.Now;
    p.Sum(k => k.Property);
    Console.WriteLine(DateTime.Now - time);

    int x = 0;
    time = DateTime.Now;
    foreach(var item in p){
        x += item.Property;
    }
    Console.WriteLine(DateTime.Now - time);

    x = 0;
    time = DateTime.Now;
    for(int i = 0, j = f; i < j; ++i){
        x += p[i].Property;
    }
    Console.WriteLine(DateTime.Now - time);
}

class Test
{
    public int Property { get; set; }
}

Mes résultats avec les optimisations du compilateur désactivées sont:

00:00:00.0570370 : Sum()
00:00:00.0250180 : Foreach()
00:00:00.0430272 : For(...)

et pour le deuxième test sont:

00:00:00.1450955 : Sum()
00:00:00.0650430 : Foreach()
00:00:00.0690510 : For()

il semble que LINQ est généralement plus lent que foreach (...) mais ce qui est bizarre pour moi, c'est que foreach (...) semble être plus rapide que for loop.

Puchacz
la source
2
pour référence ultérieure, jetez un oeil à Stopwatchen System.Diagnosticscar il est un enregistreur de temps de haute performance. (Je ne vous ai pas voté contre)
Meirion Hughes
1
Ne pas utiliser DateTime.Nowpour mesurer. Il a des performances terribles car il renvoie toujours l'heure locale. DateTime.UtcNowest plus rapide; cependant, il n'utilise toujours pas une résolution aussi élevée que la Stopwatchclasse.
György Kőszeg
3
Cela ne répond pas à la question.
Mark Pattison
Ok, merci pour le tuyau. Les scores sont très répétables, donc j'ai supposé qu'une telle résolution était suffisante
Puchacz
2
Bien que votre intention soit bonne - Mark a raison - vous ne répondez pas explicitement à la question. Je vous recommande de le changer en: "Voici comment vous pouvez le faire" et "Voici les performances du processeur de chaque option". En principe également, si vous décrivez votre méthodologie de test, vous n'avez pas besoin de nous montrer le code.
Meirion Hughes