37 votes

Obtenir les index de toutes les valeurs correspondantes de la liste en utilisant Linq

Hé, les experts de Linq ici présents,

Je viens de poser une question très similaire et je sais que la solution est probablement SUPER facile, mais je ne parviens toujours pas à comprendre comment effectuer cette tâche relativement simple de la manière la plus efficace possible en utilisant linq.

Mon scénario de base est que j'ai une liste de valeurs, par exemple, disons :

Lst1:
a
a
b
b
c
b
a
c
a

Et je veux créer une nouvelle liste qui contiendra tous les index de Lst1 où, disons, la valeur = "a". Donc, dans cet exemple, nous aurions :

LstIndexes:
0
1
6
8

Maintenant, je sais que je peux le faire avec des boucles (que je préfère éviter en faveur de Linq) et j'ai même trouvé comment le faire avec Linq de la manière suivante :

LstIndexes= Lst1.Select(Function(item As String, index As Integer) index) _
                .Where(Function(index As Integer) Lst1(index) = "a").ToList

Le problème est qu'il s'agit d'une double itération sur la liste, ce qui est donc inefficace.

Comment puis-je obtenir mon résultat de la manière la plus efficace en utilisant Linq ?

Merci !!!!

73voto

Servy Points 93720

Tout d'abord, votre code n'itère pas deux fois sur la liste, il ne l'itère qu'une fois.

Cela dit, votre Select ne fait que récupérer une séquence de tous les index ; cela est plus facile à faire avec la fonction Enumerable.Range :

var result = Enumerable.Range(0, lst1.Count)
             .Where(i => lst1[i] == "a")
             .ToList();

Il faudra s'habituer à comprendre pourquoi la liste n'est pas itérée deux fois. Je vais essayer de donner une explication de base.

Vous devez considérer la plupart des méthodes LINQ, telles que Select et Where, comme un pipeline. Chaque méthode effectue une petite partie du travail. Dans le cas de Select vous lui donnez une méthode, et il dit essentiellement : "Chaque fois que quelqu'un me demande mon prochain élément, je vais d'abord demander un élément à ma séquence d'entrée, puis utiliser la méthode dont je dispose pour le convertir en quelque chose d'autre, et enfin donner cet élément à celui qui m'utilise". Where plus ou moins, c'est dire : "chaque fois que quelqu'un me demande un article, je demande à ma séquence d'entrée un article, si la fonction dit qu'il est bon, je le transmets, sinon je continue à demander des articles jusqu'à ce que j'en obtienne un qui passe".

Donc, quand vous les enchaînez, ce qui se passe est ToList demande le premier élément, il va à Where pour son premier article, Where va à Select et lui demande son premier élément, Select va à la liste pour lui demander son premier élément. La liste fournit alors son premier élément. Select transforme ensuite cet élément en ce qu'il doit cracher (dans ce cas, juste l'int 0) et le donne à Where . Where prend cet élément et exécute sa fonction qui détermine que c'est vrai et renvoie donc 0 a ToList qui l'ajoute à la liste. Tout cela se reproduit encore 9 fois. Cela signifie que Select finira par demander chaque élément de la liste exactement une fois, et il transmettra chacun de ses résultats directement à Where qui transmet les résultats qui "passent le test" directement à ToList, qui les stocke dans une liste. Toutes les méthodes LINQ sont soigneusement conçues pour n'itérer qu'une seule fois la séquence source (lorsqu'elles sont itérées une fois).

Notez que, même si cela vous semble compliqué au premier abord, l'ordinateur n'a en fait aucun mal à faire tout cela. Les performances ne sont pas aussi élevées qu'il n'y paraît au premier abord.

7voto

Jim Points 127

Cela fonctionne, mais sans doute pas aussi bien.

var result = list1.Select((x, i) => new {x, i})
                  .Where(x => x.x == "a")
                  .Select(x => x.i);

1voto

luis_laurent Points 316

Que dites-vous de celle-ci, elle fonctionne très bien pour moi.

   static void Main(string[] args)
    {
        List<char> Lst1 = new List<char>();
        Lst1.Add('a'); 
        Lst1.Add('a');   
        Lst1.Add('b');   
        Lst1.Add('b');   
        Lst1.Add('c');   
        Lst1.Add('b');   
        Lst1.Add('a');   
        Lst1.Add('c');
        Lst1.Add('a');

        var result = Lst1.Select((c, i) => new { character = c, index = i })
                         .Where(list => list.character == 'a')
                         .ToList();
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X