Ho una lezione, in questo modo:
public class MyClass
{
public int Value { get; set; }
public bool IsValid { get; set; }
}
In realtà è molto più grande, ma questo ricrea il problema (stranezza).
Voglio ottenere la somma di Value
, dove l'istanza è valida. Finora ho trovato due soluzioni a questo.
Il primo è questo:
int result = myCollection.Where(mc => mc.IsValid).Select(mc => mc.Value).Sum();
Il secondo, tuttavia, è questo:
int result = myCollection.Select(mc => mc.IsValid ? mc.Value : 0).Sum();
Voglio ottenere il metodo più efficiente. Inizialmente pensavo che il secondo sarebbe stato più efficiente. Quindi la parte teorica di me ha iniziato ad andare "Bene, uno è O (n + m + m), l'altro è O (n + n). Il primo dovrebbe funzionare meglio con più invalidi, mentre il secondo dovrebbe funzionare meglio con meno". Ho pensato che si sarebbero comportati allo stesso modo. EDIT: E poi @Martin ha sottolineato che il Where e il Select sono stati combinati, quindi in realtà dovrebbe essere O (m + n). Tuttavia, se guardi sotto, sembra che questo non sia correlato.
Quindi l'ho messo alla prova.
(Sono più di 100 righe, quindi ho pensato che fosse meglio pubblicarlo come Gist.)
I risultati sono stati ... interessanti.
Con tolleranza allo 0%:
Le scale sono a favore di Select
e Where
, di circa ~ 30 punti.
How much do you want to be the disambiguation percentage?
0
Starting benchmarking.
Ties: 0
Where + Select: 65
Select: 36
Con una tolleranza del 2%:
È lo stesso, tranne che per alcuni erano entro il 2%. Direi che è un margine minimo di errore. Select
e Where
ora hanno solo un vantaggio di ~ 20 punti.
How much do you want to be the disambiguation percentage?
2
Starting benchmarking.
Ties: 6
Where + Select: 58
Select: 37
Con una tolleranza del 5%:
Questo è ciò che direi essere il mio massimo margine di errore. Lo rende un po 'meglio per il Select
, ma non molto.
How much do you want to be the disambiguation percentage?
5
Starting benchmarking.
Ties: 17
Where + Select: 53
Select: 31
Con una tolleranza del 10%:
Questo è fuori dal mio margine di errore, ma sono ancora interessato al risultato. Perché dà il vantaggio di Select
e Where
il venti punti che ha avuto per un po 'di tempo.
How much do you want to be the disambiguation percentage?
10
Starting benchmarking.
Ties: 36
Where + Select: 44
Select: 21
Con una tolleranza del 25%:
Questo è un modo, molto al di fuori del mio margine di errore, ma sono ancora interessato al risultato, perché Select
e Where
ancora (quasi) mantengono il vantaggio di 20 punti. Sembra che lo stia surclassando in pochi e questo è ciò che gli dà il vantaggio.
How much do you want to be the disambiguation percentage?
25
Starting benchmarking.
Ties: 85
Where + Select: 16
Select: 0
Ora, immagino che il vantaggio di 20 punti sia arrivato dal centro, dove entrambi sono tenuti a aggirare la stessa prestazione. Potrei provare a registrarlo, ma sarebbe un sacco di informazioni da prendere. Un grafico sarebbe meglio, immagino.
Quindi è quello che ho fatto.
Mostra che la Select
linea rimane stabile (prevista) e che la Select + Where
linea sale (prevista). Tuttavia, ciò che mi confonde è il motivo per cui non si incontra con il Select
50 o precedente: in effetti mi aspettavo prima del 50, poiché è stato creato un enumeratore extra per Select
e Where
. Voglio dire, questo mostra il vantaggio di 20 punti, ma non spiega il perché. Questo, immagino, è il punto principale della mia domanda.
Perché si comporta così? Dovrei fidarmi? In caso contrario, dovrei usare l'altro o questo?
Come menzionato da @KingKong nei commenti, puoi anche usare Sum
il sovraccarico che prende un lambda. Quindi le mie due opzioni sono ora cambiate in questo:
Primo:
int result = myCollection.Where(mc => mc.IsValid).Sum(mc => mc.Value);
Secondo:
int result = myCollection.Sum(mc => mc.IsValid ? mc.Value : 0);
Lo renderò un po 'più breve, ma:
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
Il vantaggio di venti punti è ancora lì, il che significa che non ha a che fare con la combinazione Where
e Select
sottolineata da @Marcin nei commenti.
Grazie per aver letto attraverso il mio muro di testo! Inoltre, se sei interessato, ecco la versione modificata che registra il CSV utilizzato da Excel.
Where
+ Select
non causa due iterazioni separate sulla raccolta di input. LINQ to Objects lo ottimizza in un'unica iterazione. Maggiori informazioni sul mio post
mc.Value
.