Elenco degli oggetti C #, come posso ottenere la somma di una proprietà


158

Ho un elenco di oggetti. Una proprietà della voce dell'oggetto singolo è importo. Come posso ottenere la somma dell'importo?

Se il mio elenco fosse di tipo doppio, potrei essere in grado di fare qualcosa del genere:

double total = myList.Sum();

Tuttavia, voglio qualcosa di simile a questo, eppure questa sintassi non è corretta.

double total = myList.amount.Sum();

Come devo fare per raggiungere questo obiettivo? Mi piacerebbe usare la funzione Somma, se possibile, invece di scorrere e calcolare il valore.

Risposte:


310
using System.Linq;

...

double total = myList.Sum(item => item.Amount);

12
È più veloce di una ricerca per interesse?
Coop

4
Sono anche interessato alla domanda di @ CodeBlend. Questo calcolo sarà più veloce di un ciclo for?
Rex,

23
@Coops - Per rispondere alla tua domanda ... usando un elenco contenente 100.000 oggetti, ogni oggetto con una singola proprietà di tipo di dati doppio, sommando la proprietà 1.000 volte usando la soluzione sopra (myList.Sum) richiede 2,44 secondi rispetto a 0,98 secondi usando foreach . Il tempo trascorso viene misurato utilizzando la classe Cronometro per la precisione. Pertanto foreach è oltre 2 volte più veloce rispetto all'utilizzo di myList.Sum.
Joe Gayetty,

36

E se devi farlo su articoli che soddisfano una condizione specifica ...

double total = myList.Where(item => item.Name == "Eggs").Sum(item => item.Amount);

11

Un'altra alternativa:

myPlanetsList.Select(i => i.Moons).Sum();

5
Invece di .Select(i => i.Moons).Sum()te puoi usare.Sum(i => i.Moons)
Mason

1
@ Mason, giusto ed è così che Alex ha affrontato il problema nella sua precedente risposta, quindi ho appena fornito un modo diverso di fare la stessa cosa.
utileBee

1
Ah sì, scusa per il mio malinteso.
Mason

Apprezzo che questa sia una risposta unica, ma le prestazioni non ne risentirebbero?
Peter Lenjo,

2

Ecco un esempio di codice che potresti eseguire per eseguire tale 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);

Lo stesso esempio per oggetti complessi è:

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

I miei risultati con le ottimizzazioni del compilatore disattivate sono:

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

e per il secondo test sono:

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

sembra che LINQ sia generalmente più lento di foreach (...) ma ciò che è strano per me è che foreach (...) sembra essere più veloce di for loop.


2
per riferimento futuro, dare un'occhiata a Stopwatchin System.Diagnosticsquanto è un registratore di tempo ad alte prestazioni. (Non ti ho sottovalutato a proposito)
Meirion Hughes,

1
Non utilizzare DateTime.Nowper la misurazione. Ha prestazioni terribili in quanto restituisce sempre l'ora locale. DateTime.UtcNowè più veloce; tuttavia, non utilizza ancora l'alta risoluzione della Stopwatchclasse.
György Kőszeg,

3
Questo non risponde alla domanda.
Mark Pattison,

Ok, grazie per il suggerimento. I punteggi sono molto ripetibili, quindi ho pensato che tale risoluzione fosse sufficiente
Puchacz,

2
Mentre la tua intenzione è buona -Mark ha ragione- non stai rispondendo esplicitamente alla domanda. Ti consiglierei di cambiarlo in: "Ecco come potresti farlo" e "Ecco le prestazioni della cpu di ogni opzione". Inoltre, in linea di principio, se descrivi la tua metodologia di test, non devi mostrarci il codice.
Meirion Hughes,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.