Tengo una clase como esta:
public class MyClass
{
public int Value { get; set; }
public bool IsValid { get; set; }
}
De hecho, es mucho más grande, pero esto recrea el problema (rareza).
Quiero obtener la suma de Value
, donde la instancia es válida. Hasta ahora, he encontrado dos soluciones para esto.
El primero es este:
int result = myCollection.Where(mc => mc.IsValid).Select(mc => mc.Value).Sum();
La segunda, sin embargo, es esta:
int result = myCollection.Select(mc => mc.IsValid ? mc.Value : 0).Sum();
Quiero obtener el método más eficiente. Al principio, pensé que el segundo sería más eficiente. Entonces la parte teórica de mí comenzó a decir "Bueno, uno es O (n + m + m), el otro es O (n + n). El primero debería funcionar mejor con más inválidos, mientras que el segundo debería funcionar mejor con menos". Pensé que actuarían por igual. EDITAR: Y luego @Martin señaló que el Dónde y el Seleccionar se combinaron, por lo que en realidad debería ser O (m + n). Sin embargo, si mira a continuación, parece que esto no está relacionado.
Así que lo puse a prueba.
(Son más de 100 líneas, así que pensé que era mejor publicarlo como un Gist.)
Los resultados fueron ... interesantes.
Con 0% de tolerancia de empate:
Las escalas están a favor de Select
y Where
, en aproximadamente ~ 30 puntos.
How much do you want to be the disambiguation percentage?
0
Starting benchmarking.
Ties: 0
Where + Select: 65
Select: 36
Con 2% de tolerancia de empate:
Es lo mismo, excepto que para algunos estaban dentro del 2%. Yo diría que es un margen mínimo de error. Select
y Where
ahora solo tengo una ventaja de ~ 20 puntos.
How much do you want to be the disambiguation percentage?
2
Starting benchmarking.
Ties: 6
Where + Select: 58
Select: 37
Con 5% de tolerancia de empate:
Esto es lo que yo diría que es mi margen de error máximo. Lo hace un poco mejor para el Select
, pero no mucho.
How much do you want to be the disambiguation percentage?
5
Starting benchmarking.
Ties: 17
Where + Select: 53
Select: 31
Con 10% de tolerancia de empate:
Esto está fuera de mi margen de error, pero todavía estoy interesado en el resultado. Porque da la Select
y Where
el punto de veinte conducir que ha tenido desde hace un tiempo.
How much do you want to be the disambiguation percentage?
10
Starting benchmarking.
Ties: 36
Where + Select: 44
Select: 21
Con 25% de tolerancia de empate:
Esto está muy, muy lejos de mi margen de error, pero todavía estoy interesado en el resultado, porque todavíaSelect
y (casi) mantienen su ventaja de 20 puntos. Parece que lo está superando en unos pocos, y eso es lo que le da el liderazgo.Where
How much do you want to be the disambiguation percentage?
25
Starting benchmarking.
Ties: 85
Where + Select: 16
Select: 0
Ahora, supongo que la ventaja de 20 puntos venía del medio, donde los dos están obligados a obtener alrededor la misma actuación. Podría intentar registrarlo, pero sería una gran cantidad de información para asimilar. Supongo que un gráfico sería mejor.
Entonces eso fue lo que hice.
Muestra que la Select
línea se mantiene estable (esperada) y que la Select + Where
línea sube (esperada). Sin embargo, lo que me desconcierta es por qué no cumple con los Select
50 o antes: de hecho, esperaba antes de los 50, ya que se tenía que crear un enumerador adicional para el Select
yWhere
. Quiero decir, esto muestra la ventaja de 20 puntos, pero no explica por qué. Este, supongo, es el punto principal de mi pregunta.
¿Por qué se comporta así? ¿Debo confiar en eso? Si no, ¿debería usar el otro o este?
Como @KingKong mencionó en los comentarios, también puede usar Sum
la sobrecarga de un lambda. Entonces mis dos opciones ahora se cambian a esto:
Primero:
int result = myCollection.Where(mc => mc.IsValid).Sum(mc => mc.Value);
Segundo:
int result = myCollection.Sum(mc => mc.IsValid ? mc.Value : 0);
Lo haré un poco más corto, pero:
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
La ventaja de veinte puntos sigue ahí, lo que significa que no tiene que ver con el Where
ySelect
combinación combinación señalada por @Marcin en los comentarios.
¡Gracias por leer mi muro de texto! Además, si está interesado, aquí está la versión modificada que registra el CSV que toma Excel.
Where
+ Select
no causa dos iteraciones separadas sobre la colección de entrada. LINQ to Objects lo optimiza en una iteración. Leer más en mi blog
mc.Value
.