J'ai une classe, comme celle-ci:
public class MyClass
{
public int Value { get; set; }
public bool IsValid { get; set; }
}
En fait, c'est beaucoup plus gros, mais cela recrée le problème (bizarrerie).
Je veux obtenir la somme des Value
, où l'instance est valide. Jusqu'à présent, j'ai trouvé deux solutions à cela.
Le premier est celui-ci:
int result = myCollection.Where(mc => mc.IsValid).Select(mc => mc.Value).Sum();
La deuxième, cependant, est la suivante:
int result = myCollection.Select(mc => mc.IsValid ? mc.Value : 0).Sum();
Je veux obtenir la méthode la plus efficace. J'ai d'abord pensé que le second serait plus efficace. Ensuite, la partie théorique de moi a commencé à dire "Eh bien, l'un est O (n + m + m), l'autre est O (n + n). Le premier devrait mieux fonctionner avec plus d'invalides, tandis que le second devrait mieux fonctionner avec moins". Je pensais qu'ils fonctionneraient également. EDIT: Et puis @Martin a souligné que le Where et le Select étaient combinés, donc cela devrait en fait être O (m + n). Cependant, si vous regardez ci-dessous, il semble que cela ne soit pas lié.
Alors je l'ai mis à l'épreuve.
(C'est plus de 100 lignes, alors j'ai pensé qu'il valait mieux l'afficher sous forme de résumé.)
Les résultats étaient ... intéressants.
Avec 0% de tolérance de cravate:
Les échelles sont en faveur de Select
et Where
, d'environ ~ 30 points.
How much do you want to be the disambiguation percentage?
0
Starting benchmarking.
Ties: 0
Where + Select: 65
Select: 36
Avec une tolérance de cravate de 2%:
C'est la même chose, sauf que pour certains, ils se situaient à moins de 2%. Je dirais que c'est une marge d'erreur minimale. Select
et Where
maintenant seulement une avance d'environ 20 points.
How much do you want to be the disambiguation percentage?
2
Starting benchmarking.
Ties: 6
Where + Select: 58
Select: 37
Avec une tolérance de cravate de 5%:
C'est ce que je dirais être ma marge d'erreur maximale. Cela le rend un peu meilleur pour le Select
, mais pas beaucoup.
How much do you want to be the disambiguation percentage?
5
Starting benchmarking.
Ties: 17
Where + Select: 53
Select: 31
Avec 10% de tolérance de cravate:
C'est loin de ma marge d'erreur, mais je suis toujours intéressé par le résultat. Parce qu'il donne Select
et Where
vingt points d' avance , il a eu pendant un certain temps maintenant.
How much do you want to be the disambiguation percentage?
10
Starting benchmarking.
Ties: 36
Where + Select: 44
Select: 21
Avec 25% de tolérance de cravate:
C'est ainsi, chemin de ma marge d'erreur, mais je suis toujours intéressé par le résultat, parce que la Select
et Where
encore (presque) ont conservé leur avance de 20 points. Il semble qu'il le surclasse dans quelques-uns, et c'est ce qui lui donne la tête.
How much do you want to be the disambiguation percentage?
25
Starting benchmarking.
Ties: 85
Where + Select: 16
Select: 0
Maintenant, je devine que la tête de 20 points est venu du milieu, où ils sont tous deux liés à obtenir autour de la même performance. Je pourrais essayer de l'enregistrer, mais ce serait tout un tas d'informations à intégrer. Un graphique serait mieux, je suppose.
C'est donc ce que j'ai fait.
Cela montre que la Select
ligne reste stable (attendue) et que la Select + Where
ligne monte (attendue). Cependant, ce qui me laisse perplexe, c'est pourquoi il ne rencontre pas le Select
à 50 ou avant: en fait, je m'attendais à plus de 50, car un énumérateur supplémentaire devait être créé pour le Select
et Where
. Je veux dire, cela montre l'avance de 20 points, mais cela n'explique pas pourquoi. Tel est, je suppose, le point principal de ma question.
Pourquoi se comporte-t-il ainsi? Dois-je lui faire confiance? Sinon, devrais-je utiliser l'autre ou celui-ci?
Comme @KingKong l'a mentionné dans les commentaires, vous pouvez également utiliser Sum
la surcharge de qui prend un lambda. Donc, mes deux options sont maintenant modifiées pour ceci:
Première:
int result = myCollection.Where(mc => mc.IsValid).Sum(mc => mc.Value);
Seconde:
int result = myCollection.Sum(mc => mc.IsValid ? mc.Value : 0);
Je vais le raccourcir un peu, mais:
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
L'avance de vingt points est toujours là, ce qui signifie qu'elle n'a pas à voir avec la combinaison Where
et Select
indiquée par @Marcin dans les commentaires.
Merci d'avoir lu mon mur de texte! De plus, si vous êtes intéressé, voici la version modifiée qui enregistre le CSV qu'Excel prend.
Where
+ Select
ne provoque pas deux itérations séparées sur la collection d'entrée. LINQ to Objects l'optimise en une seule itération. Lire la suite sur mon article de blog
mc.Value
.