Eu tenho uma classe, assim:
public class MyClass
{
public int Value { get; set; }
public bool IsValid { get; set; }
}
Na verdade, é muito maior, mas isso recria o problema (esquisitice).
Eu quero obter a soma do Value
, onde a instância é válida. Até agora, encontrei duas soluções para isso.
O primeiro é o seguinte:
int result = myCollection.Where(mc => mc.IsValid).Select(mc => mc.Value).Sum();
O segundo, no entanto, é o seguinte:
int result = myCollection.Select(mc => mc.IsValid ? mc.Value : 0).Sum();
Eu quero obter o método mais eficiente. A princípio, pensei que o segundo seria mais eficiente. Então a parte teórica de mim começou a dizer "Bem, um é O (n + m + m), o outro é O (n + n). O primeiro deve ter um desempenho melhor com mais inválidos, enquanto o segundo deve ter um desempenho melhor com menos". Eu pensei que eles teriam um desempenho igual. EDIT: E então @Martin apontou que o Where e o Select foram combinados, portanto deve ser O (m + n). No entanto, se você olhar abaixo, parece que isso não está relacionado.
Então eu testei.
(São mais de 100 linhas, então pensei que era melhor publicá-lo como um Gist.)
Os resultados foram ... interessantes.
Com tolerância de empate de 0%:
As escalas são a favor Select
e Where
, em cerca de ~ 30 pontos.
How much do you want to be the disambiguation percentage?
0
Starting benchmarking.
Ties: 0
Where + Select: 65
Select: 36
Com 2% de tolerância de empate:
É o mesmo, exceto que para alguns eles estavam dentro de 2%. Eu diria que é uma margem mínima de erro. Select
e Where
agora tem apenas uma vantagem de ~ 20 pontos.
How much do you want to be the disambiguation percentage?
2
Starting benchmarking.
Ties: 6
Where + Select: 58
Select: 37
Com 5% de tolerância de empate:
Isso é o que eu diria ser a minha margem máxima de erro. Isso torna um pouco melhor para o Select
, mas não muito.
How much do you want to be the disambiguation percentage?
5
Starting benchmarking.
Ties: 17
Where + Select: 53
Select: 31
Com 10% de tolerância de empate:
Isso está fora da minha margem de erro, mas ainda estou interessado no resultado. Porque dá a Select
e Where
a vantagem de vinte pontos que já há algum tempo.
How much do you want to be the disambiguation percentage?
10
Starting benchmarking.
Ties: 36
Where + Select: 44
Select: 21
Com 25% de tolerância de empate:
Esta é a maneira, maneira fora da minha margem de erro, mas eu ainda estou interessado no resultado, porque o Select
e Where
ainda (quase) manter sua vantagem de 20 pontos. Parece que ele está superando em poucos, e é isso que está dando a liderança.
How much do you want to be the disambiguation percentage?
25
Starting benchmarking.
Ties: 85
Where + Select: 16
Select: 0
Agora, eu estou supondo que a liderança de 20 pontos veio do meio, onde ambos são obrigados a ficar em torno do mesmo desempenho. Eu poderia tentar registrá-lo, mas seria uma carga de informações para absorver. Um gráfico seria melhor, eu acho.
Então foi o que eu fiz.
Isso mostra que a Select
linha se mantém estável (esperada) e que a Select + Where
linha sobe (esperada). No entanto, o que me intriga é o motivo pelo qual ele não se encontra com os Select
50 ou mais anteriores: na verdade, eu esperava mais de 50, pois um enumerador extra precisava ser criado para o Select
e Where
. Quero dizer, isso mostra a vantagem de 20 pontos, mas não explica o porquê. Acho que esse é o ponto principal da minha pergunta.
Por que se comporta assim? Devo confiar nisso? Caso contrário, devo usar o outro ou este?
Como o @KingKong mencionado nos comentários, você também pode usar Sum
a sobrecarga de uma lambda. Então, minhas duas opções agora foram alteradas para isso:
Primeiro:
int result = myCollection.Where(mc => mc.IsValid).Sum(mc => mc.Value);
Segundo:
int result = myCollection.Sum(mc => mc.IsValid ? mc.Value : 0);
Vou torná-lo um pouco mais curto, mas:
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
A liderança de vinte pontos ainda está lá, o que significa que não tem a ver com a combinação Where
e Select
apontada por @Marcin nos comentários.
Obrigado por ler minha parede de texto! Além disso, se você estiver interessado, aqui está a versão modificada que registra o CSV que o Excel recebe.
Where
+ Select
não causa duas iterações separadas sobre a coleção de entrada. O LINQ to Objects otimiza-o em uma iteração. Leia mais na minha postagem
mc.Value
são caros .