C # Lista de objetos, como obtenho a soma de uma propriedade

158

Eu tenho uma lista de objetos. Uma propriedade da entrada de objeto individual é a quantidade. Como obtenho a soma do valor?

Se minha lista era do tipo double, talvez eu pudesse fazer algo assim:

double total = myList.Sum();

No entanto, eu quero algo semelhante a isso, mas essa sintaxe está incorreta.

double total = myList.amount.Sum();

Como devo fazer isso? Eu adoraria usar a função Sum, se possível, em vez de percorrer e calcular o valor.

Joseph U.
fonte

Respostas:

310
using System.Linq;

...

double total = myList.Sum(item => item.Amount);
Alex LE
fonte
12
Isso é mais rápido do que foreach por interesse?
Coops
4
Também estou interessado na pergunta do @ CodeBlend. Esse cálculo será mais rápido que um loop for?
Rex
23
@Coops - Para responder sua pergunta ... usando uma lista contendo 100.000 objetos, cada objeto com uma única propriedade do tipo de dados double, resumindo a propriedade 1.000 vezes usando a solução acima (myList.Sum) leva 2,44 segundos em comparação com 0,98 segundos usando foreach . O tempo decorrido é medido usando a classe Cronômetro para precisão. Portanto, o foreach é duas vezes mais rápido que o myList.Sum.
Joe Gayetty
36

E se você precisar fazer isso em itens que correspondam a uma condição específica ...

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

Outra alternativa:

myPlanetsList.Select(i => i.Moons).Sum();
usefulBee
fonte
5
Em vez de .Select(i => i.Moons).Sum()você pode usar.Sum(i => i.Moons)
Mason
1
@Mason, certo, e foi assim que Alex abordou o problema em sua resposta anterior, então forneci uma maneira diferente de fazer a mesma coisa.
usar o seguinte comando
1
Ah sim, desculpe pelo meu equívoco.
Mason
Compreendo que esta é uma resposta única, mas o desempenho não sofrerá?
Peter Lenjo
2

Aqui está um código de exemplo que você pode executar para fazer esse teste:

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

O mesmo exemplo para objeto complexo é:

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

Meus resultados com as otimizações do compilador desativadas são:

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

e para o segundo teste são:

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

parece que o LINQ é geralmente mais lento que o foreach (...), mas o que é estranho para mim é que o foreach (...) parece ser mais rápido do que o loop.

Puchacz
fonte
2
para referência futura, dar uma olhada Stopwatchem System.Diagnosticscomo é um gravador de tempo de alto desempenho. (Eu não te diminuía de votar)
Meirion Hughes
1
Não use DateTime.Nowpara medir. Tem um desempenho terrível, pois sempre retorna a hora local. DateTime.UtcNowé mais rápido; no entanto, ele ainda não usa a resolução mais alta que a Stopwatchclasse.
György Kőszeg
3
Isso não responde à pergunta.
Mark Pattison
Ok, obrigado pela dica. De pontuação são muito repetitivo então eu assumi que tal resolução é suficiente
Puchacz
2
Embora sua intenção seja boa - Mark esteja certo - você não está respondendo explicitamente à pergunta. Eu recomendo que você mude para: "Aqui está como você pode fazê-lo" e "Aqui está o desempenho da CPU de cada opção". Também em princípio, se você descrever sua metodologia de teste, não precisará nos mostrar o código.
Meirion Hughes