J'ai un List<bool>
avec beaucoup de valeurs. Quelle est la façon la plus efficace de vérifier si chaque élément de la liste est égal à false
?
Une solution beaucoup plus rapide, non mentionnée ici, utilise Contains
if (!myList.Contains(true))
// Great success - all values false!
J'ai comparé Contains
contre IEnumerable.Any
et Contains
revient plus rapidement. Dans mes tests IEnumerable.All
fait la même chose que IEnumerable.Any
, un algorithme similaire est peut-être utilisé pour ces deux fonctions sous le capot. J'ai également vérifié IEnumerable.Exists
qui a mieux performé que IEnumerable.Any
et IEnumerable.All
, mais était toujours plus lent que Contains
.
Sur une liste de 10 000 000 d'entrées booléennes (j'ai aussi essayé 0 et 1 entrées, avec des résultats similaires), j'ai trouvé les métriques suivantes:
Écoulé via Tout = 95 ms
Écoulé via tous = 88 ms
Écoulé via Exists = 27 ms
Écoulé via contient = 17 ms
Contient est ~ 5.59x plus rapide que tout !
Testé avec le code suivant:
// setup initial vars
var myList = new List<bool>();
for (int x = 0; x < 10000000; x++)
myList.Add(false);
var containsAllFalse = false;
Stopwatch sw = new Stopwatch();
// start test
sw.Start();
containsAllFalse = !myList.Any(x => x);
sw.Stop();
// get result for Any
var timeAny = sw.ElapsedMilliseconds;
// reset variable state (just in case it affects anything)
containsAllFalse = false;
// start test 2
sw.Restart();
containsAllFalse = myList.All(x => x == false);
sw.Stop();
// get result for All
var timeAll = sw.ElapsedMilliseconds;
// reset variable state (just in case it affects anything)
containsAllFalse = false;
// start test 3
sw.Restart();
containsAllFalse = !myList.Exists(x => x == true);
sw.Stop();
// get result for All
var timeExists = sw.ElapsedMilliseconds;
// reset variable state (just in case it affects anything)
containsAllFalse = false;
// start test 4
sw.Restart();
containsAllFalse = !myList.Contains(true);
sw.Stop();
// get result from Contains
var timeContains = sw.ElapsedMilliseconds;
// print results
var percentFaster = Math.Round((double)timeAny / timeContains, 2);
Console.WriteLine("Elapsed via Any = {0}ms", timeAny);
Console.WriteLine("Elapsed via All = {0}ms", timeAll);
Console.WriteLine("Elapsed via Exists = {0}ms", timeExists);
Console.WriteLine("Elapsed via Contains = {0}ms", timeContains);
Console.WriteLine("Contains is ~{0}x faster than Any!", percentFaster);
Notez que cela ne fonctionnera qu'avec des types où le type ne peut avoir que deux états (c'est-à-dire qu'il ne fonctionnera pas avec des variables de> 2 états, comme Nullable<bool>
)
Vous pouvez utiliser Enumerable.Any
il trouvera satisfaire la condition lors de la première correspondance. Comme Habib l'a dit à juste titre, il vaut mieux utiliser Any comme Enumerable.Tout retournerait vrai pour une liste vide de booléens.
!lst.Any(c=> c == true);
OU utilisez Enumerable.All
lst.All(c=> c == false);
Je suis d'accord avec l'utilisation de IEnumerable.Any / All . Cependant, je ne suis pas d'accord avec la réponse actuellement la plus votée (qui était erronée au moment de la rédaction de ce document) et plusieurs des commentaires associés de Any vs All.
Ces opérations suivantes sont équivalentes sémantiquement. Notez que les négations sont appliquées à la fois à l'intérieur, sur le prédicat et sur le résultat de l'opération.
!l.Any(x => f(x))
l.All(x => !f(x))
Maintenant, dans ce cas, nous recherchons donc:
Si ce n'est pas le cas où il y a une valeur vraie .
!l.Any(x => x) // f(x) = x == true
Ou ,
Il est vrai que chaque valeur est pas vraie.
l.All(x => !x) // f'(x) = !f(x) = !(x == true)
Il n'y a rien de spécial pour les listes vides, le résultat est le même: par ex. !empty.Any(..)
est faux, tout comme empty.All(..)
et la relation d'équivalence ci-dessus reste valide.
De plus, les deux formulaires sont évalués paresseusement et nécessitent le même nombre d'évaluations dans LINQ To Objects ; en interne, la différence, pour une implémentation de séquence, est simplement de nier la vérification du prédicat et de la valeur de résultat.
Vous pouvez utiliser LINQ's
All
méthode:
list.All(x => x == false);
Cela renverra false
immédiatement s'il trouve une valeur égale à true
.