Mam taką klasę:
public class MyClass
{
public int Value { get; set; }
public bool IsValid { get; set; }
}
W rzeczywistości jest znacznie większy, ale to odtwarza problem (dziwność).
Chcę uzyskać sumę Value
, gdzie instancja jest prawidłowa. Jak dotąd znalazłem dwa rozwiązania tego problemu.
Pierwsza z nich to:
int result = myCollection.Where(mc => mc.IsValid).Select(mc => mc.Value).Sum();
Drugi to jednak:
int result = myCollection.Select(mc => mc.IsValid ? mc.Value : 0).Sum();
Chcę uzyskać najbardziej wydajną metodę. Na początku myślałem, że ten drugi będzie bardziej wydajny. Wtedy część teoretyczna mnie zaczęła mówić "No cóż, jedna to O (n + m + m), druga to O (n + n). Pierwsza powinna działać lepiej z większą liczbą inwalidów, a druga powinna działać lepiej mniej ”. Pomyślałem, że będą działać równie dobrze. EDYCJA: A potem @Martin wskazał, że Gdzie i Wybierz zostały połączone, więc powinno to być O (m + n). Jeśli jednak spojrzysz poniżej, wygląda na to, że nie ma to związku.
Więc wystawiłem to na próbę.
(To ponad 100 wierszy, więc pomyślałem, że lepiej będzie opublikować to jako streszczenie)
. Wyniki były ... interesujące.
Z 0% tolerancją krawata:
Skale są na korzyść Select
i Where
, o około ~ 30 punktów.
How much do you want to be the disambiguation percentage?
0
Starting benchmarking.
Ties: 0
Where + Select: 65
Select: 36
Z 2% tolerancją krawata:
To jest to samo, z wyjątkiem tego, że dla niektórych były w granicach 2%. Powiedziałbym, że to minimalny margines błędu. Select
a Where
teraz mają tylko ~ 20 punktów przewagi.
How much do you want to be the disambiguation percentage?
2
Starting benchmarking.
Ties: 6
Where + Select: 58
Select: 37
Z 5% tolerancją krawata:
To właśnie powiedziałbym, że jest to mój maksymalny margines błędu. To sprawia, że jest trochę lepiej Select
, ale niewiele.
How much do you want to be the disambiguation percentage?
5
Starting benchmarking.
Ties: 17
Where + Select: 53
Select: 31
Z 10% tolerancją krawata:
To jest poza moim marginesem błędu, ale nadal jestem zainteresowany wynikiem. Bo to daje Select
i Where
punkt dwadzieścia prowadzić to miałem na chwilę teraz.
How much do you want to be the disambiguation percentage?
10
Starting benchmarking.
Ties: 36
Where + Select: 44
Select: 21
Z 25% tolerancją krawata:
To jest sposób, aby wyjść poza mój margines błędu, ale nadal jestem zainteresowany wynikiem, ponieważ Select
i Where
nadal (prawie) utrzymują swoją 20-punktową przewagę. Wygląda na to, że deklasuje go w kilku wyraźnych i to właśnie daje mu przewagę.
How much do you want to be the disambiguation percentage?
25
Starting benchmarking.
Ties: 85
Where + Select: 16
Select: 0
Zgaduję, że 20-punktowa przewaga nadeszła ze środka, gdzie obaj będą musieli obejść ten sam występ. Mógłbym spróbować to zarejestrować, ale byłoby to całe mnóstwo informacji do zebrania. Wykres byłby lepszy, jak sądzę.
Więc to właśnie zrobiłem.
Pokazuje, że Select
linia pozostaje stabilna (oczekiwana) i że Select + Where
linia wznosi się (oczekiwana). Zastanawiające mnie jednak, dlaczego nie spotyka się z Select
50 lub wcześniej: tak naprawdę spodziewałem się wcześniej niż 50, ponieważ trzeba było stworzyć dodatkowy wyliczający dla Select
i Where
. To znaczy, to pokazuje 20-punktową przewagę, ale nie wyjaśnia dlaczego. To chyba jest główny punkt mojego pytania.
Dlaczego tak się zachowuje? Powinienem mu ufać? Jeśli nie, powinienem użyć drugiego czy tego?
Jak @KingKong wspomniał w komentarzach, możesz również użyć Sum
przeciążenia, które pobiera lambdę. Więc moje dwie opcje są teraz zmienione na:
Pierwszy:
int result = myCollection.Where(mc => mc.IsValid).Sum(mc => mc.Value);
Druga:
int result = myCollection.Sum(mc => mc.IsValid ? mc.Value : 0);
Mam zamiar to trochę skrócić, ale:
How much do you want to be the disambiguation percentage?
0
Starting benchmarking.
Ties: 0
Where: 60
Sum: 41
How much do you want to be the disambiguation percentage?
2
Starting benchmarking.
Ties: 8
Where: 55
Sum: 38
How much do you want to be the disambiguation percentage?
5
Starting benchmarking.
Ties: 21
Where: 49
Sum: 31
How much do you want to be the disambiguation percentage?
10
Starting benchmarking.
Ties: 39
Where: 41
Sum: 21
How much do you want to be the disambiguation percentage?
25
Starting benchmarking.
Ties: 85
Where: 16
Sum: 0
Dwudziestopunktowa przewaga wciąż istnieje, co oznacza, że nie ma nic wspólnego z kombinacją Where
i Select
wskazaną przez @Marcin w komentarzach.
Dziękuję za przeczytanie mojej ściany tekstu! Ponadto, jeśli jesteś zainteresowany, oto zmodyfikowana wersja, która rejestruje plik CSV pobierany przez program Excel.
Where
+ Select
nie powoduje dwóch oddzielnych iteracji po kolekcji danych wejściowych. LINQ to Objects optymalizują go w jednej iteracji. Przeczytaj więcej na moim blogu
mc.Value
niej.