C # Nesnelerin listesi, bir özelliğin toplamını nasıl alabilirim


158

Nesneler listem var. Tek tek nesne girişinin bir özelliği miktardır. Tutarın toplamını nasıl alabilirim?

Listem türü çift ise, ben böyle bir şey yapmak mümkün olabilir:

double total = myList.Sum();

Ancak buna benzer bir şey istiyorum, ancak bu sözdizimi yanlış.

double total = myList.amount.Sum();

Bunu nasıl başarabilirim? Döngü ve değeri hesaplamak yerine mümkünse Sum işlevini kullanmak isterdim.

Yanıtlar:


310
using System.Linq;

...

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

12
Bu öngörüldüğünden daha hızlı mı?
Coops

4
Ayrıca @ CodeBlend'in sorusuyla da ilgileniyorum. Bu hesaplama bir for döngüsünden daha hızlı mı olacak?
rex

23
@Coops - Sorunuzu cevaplamak için ... 100.000 nesne içeren bir liste kullanarak, her bir veri türünün tek bir özelliğine sahip olan, yukarıdaki çözümü (myList.Sum) kullanarak özelliği 1.000 kez toplayan, foreach kullanarak 0.98 saniyeye kıyasla 2.44 saniye sürer . Geçen süre, doğruluk için Kronometre sınıfı kullanılarak ölçülür. Bu nedenle, foreach myList.Sum kullanmaktan 2 kat daha hızlıdır.
Joe Gayetty

36

Ve belirli bir koşulla eşleşen öğeler üzerinde yapmanız gerekiyorsa ...

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

11

Başka bir alternatif:

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

5
Bunun yerine .Select(i => i.Moons).Sum()kullanabilirsiniz.Sum(i => i.Moons)
Mason

1
@Mason, doğru ve Alex, önceki cevabında soruna bu şekilde yaklaştı, bu yüzden aynı şeyi yapmanın farklı bir yolunu sağladım.
usefulBee

1
Ah evet, yanlış anlayışım için üzgünüm.
Mason

Bunun benzersiz bir cevap olduğunu takdir ediyorum, ancak performans zarar görmez mi?
Peter Lenjo

2

Bu tür bir test yapmak için çalıştırabileceğiniz örnek kod:

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

Karmaşık nesne için aynı örnek:

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

Derleyici optimizasyonları kapalı sonuçlarım:

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

ve ikinci test için:

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

LINQ genellikle foreach (...) 'dan daha yavaş görünüyor ama benim için garip olan şey foreach (...)' in loop 'dan daha hızlı olduğu.


2
İleride başvurmak için, bir göz Stopwatchiçinde System.Diagnosticsbu yüksek performanslı zamanı kaydedici olduğu gibi. (Sana btw indirmedim)
Meirion Hughes

1
DateTime.NowÖlçüm için kullanmayın . Her zaman yerel saati döndürdüğü için korkunç bir performansa sahiptir. DateTime.UtcNowdaha hızlı; ancak yine de Stopwatchsınıf kadar yüksek çözünürlük kullanmaz .
György Kőszeg

3
Bu soruya cevap vermiyor.
Mark Pattison

Tamam, bahşiş için teşekkürler. Puan çok tekrarlanabilir bu yüzden böyle bir çözüm yeterli olduğunu varsaydım
Puchacz

2
Niyetiniz iyi olsa da -Mark haklıdır- soruyu açıkça cevaplamıyorsunuz. Bunu şu şekilde değiştirmenizi öneriyorum: "Bunu nasıl yapabileceğiniz" ve "Her seçeneğin işlemci performansı". Ayrıca prensip olarak test metodolojinizi açıklarsanız bize kodu göstermeniz gerekmez.
Meirion Hughes
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.