web-dev-qa-db-fra.com

Le moyen le plus efficace de rechercher si une valeur existe dans une liste C #

En C # si j'ai une liste de type bool. Quel est le moyen le plus rapide de déterminer si la liste contient une valeur vraie? Je n'ai pas besoin de savoir combien ou où se trouve la vraie valeur. J'ai juste besoin de savoir s'il en existe un. Je vais chercher beaucoup de listes extrêmement volumineuses.

12
Aaron Benzel

Utilisez list.Contains (true) ou list.Any (true) . Pour une liste normale, la complexité est O (n). Étant donné que Any () est une méthode d’extension nécessitant l’appel de délégués, la méthode Contains () est peut-être encore un peu plus rapide. Mais pour être sûr, je voudrais simplement tester les deux avec une grande collection.

7
treze

Utilisez simplement bool trueInList = list.Contains(true);. Cela boucle la liste jusqu'à ce qu'il y ait une true.

Pourquoi avez-vous besoin de quelque chose de plus rapide avec un cas d'utilisation aussi simple?

20
Rango

Vous pouvez utiliser Any ().

list.Any(b => b);
5
user707727

Essaye ça:

var result = myBoolList.Any(i => i==true);
3

Ce sera le moyen le plus rapide:

static bool AnySet(List<bool> data)
{
    for (int i = 0; i < data.Count; ++i)
        if (data[i])
            return true;

    return false;
}

Méfiez-vous des réponses impliquant Linq. Ils seront plus lents, comme le montre ce programme de test (en fait, le Linq est plus de 12 fois plus lent!

Cela démontre également que (sur mon système au moins) la boucle codée à la main est environ 3,5 fois plus rapide que List.Contains().

Résultats sur mon PC (Windows 8 x64, programme compilé en x86)

Times in seconds

01.0994496 data.Any() list
01.1147795 data.Any() enumerable
00.1215951 hand-rolled loop
00.4240996 list.Contains()

J'ai testé cela sur plusieurs systèmes, y compris un ordinateur portable de 5 ans sous XP et un nouveau PC sous Windows 8, avec des résultats similaires.

(N'oubliez pas de faire vos timings à partir d'une version RELEASE.)

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace ConsoleApplication1
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            int size = 10000000;
            int count = 10;
            List<bool> data = new List<bool>(size);

            for (int i = 0; i < size; ++i)
                data.Add(false);

            var sw = Stopwatch.StartNew();

            for (int trial = 0; trial < 5; ++trial)
            {
                sw.Restart();

                for (int i = 0; i < count; ++i)
                    AnySet1(data);

                Console.WriteLine(sw.Elapsed + " data.Any() list");
                sw.Restart();

                for (int i = 0; i < count; ++i)
                    AnySet2(data);

                Console.WriteLine(sw.Elapsed + " data.Any() enumerable");
                sw.Restart();

                for (int i = 0; i < count; ++i)
                    AnySet3(data);

                Console.WriteLine(sw.Elapsed + " hand-rolled loop");
                sw.Restart();

                for (int i = 0; i < count; ++i)
                    AnySet4(data);

                Console.WriteLine(sw.Elapsed + " list.Contains()");

                Console.WriteLine();
            }
        }

        static bool AnySet1(List<bool> data)
        {
            return data.Any(b => b);
        }

        static bool AnySet2(IEnumerable<bool> data)
        {
            return data.Any(b => b);
        }

        static bool AnySet3(List<bool> data)
        {
            for (int i = 0; i < data.Count; ++i)
                if (data[i])
                    return true;

            return false;
        }

        static bool AnySet4(List<bool> data)
        {
            return data.Contains(true);
        }
    }
}

Alors, pourquoi diable List.Contains() serait-il plus lent? Eh bien, utilisons réflecteur pour regarder sa mise en œuvre:

bool Contains(T item)
{
    if (item == null)
    {
        for (int j = 0x0; j < this._size; j++)
        {
            if (this._items[j] == null)
            {
                return true;
            }
        }
        return false;
    }
    EqualityComparer<T> comparer = EqualityComparer<T>.Default;
    for (int i = 0x0; i < this._size; i++)
    {
        if (comparer.Equals(this._items[i], item))
        {
            return true;
        }
    }
    return false;
}

Aha! Tout est révélé! Il appelle comparer.Equals() pour chaque élément. Pas étonnant que ce soit plus lent!


Deux autres choses que je voudrais mentionner:

  • Si vous voulez vraiment une vitesse maximale, vous devriez utiliser un tableau simple plutôt qu'une liste.
  • Pour une vitesse maximale possible, vous pouvez écrire votre propre version d'une BitArray dans laquelle vous stockez les bits bools sous forme de bits dans des entiers non signés 32 bits. Ensuite, vous pouvez vraiment zoomer en vérifiant 32 bits à la fois avec un simple != 0 sur chaque uint.
2
Matthew Watson

Vous utilisez le Any(...)

list.Any(c => c == true);

ou juste

list.Any(c => c);
1
Jens Kloster

Cette réponse fournit un angle différent sur ceci: Pourquoi stocker les bools dans une liste? Stockez-les sous deux ints: int falseCount; int trueCount;.

Contains-testing est aussi simple que: trueCount > 0

En supposant que vous ayez besoin de la liste, utilisez List.Contains car il recherche directement le tableau sous-jacent.

Il serait encore plus rapide d'extraire le tableau sous-jacent à l'aide de la réflexion et de le rechercher dans une boucle de comparaison codée en dur. Vous pouvez utiliser la valeur true littérale pour comparer chaque élément. Vous pouvez même dérouler la boucle ou faire des tours de code non sécurisés.

1
usr
bool val = false;
Foreach(bool val in listofvalue)
{
   val |= val;
}

if(val)
print "List contain true value"

else

print "List contain false value"
0
vikky

Vous pouvez utiliser la méthode BinarySearch de la liste.

if(list.BinarySearch(true) > 0){...}
0
Saeed