Comment obtenir l'index d'un élément dans une liste en une seule étape?

193

Comment puis-je trouver l'index d'un élément dans une liste sans le parcourir?

Actuellement, cela ne semble pas très agréable - rechercher deux fois le même élément dans la liste, juste pour obtenir l'index:

var oProp = something;

int theThingIActuallyAmInterestedIn = myList.IndexOf(myList.Single(i => i.Prop == oProp));
Daniel Robinson
la source

Réponses:

434

Que diriez- vous de la méthode List.FindIndex :

int index = myList.FindIndex(a => a.Prop == oProp);

Cette méthode effectue une recherche linéaire; par conséquent, cette méthode est une opération O (n), où n est Count.

Si l'article n'est pas trouvé, il renverra -1

Alex Filipovici
la source
2
Et alors int index?
Dylan Czenski
2
@DylanChensky, il a trop
codé
9
Pour référence, si l'article n'est pas trouvé; il reviendra -1
Daniel Filipe
102

Pour les types simples, vous pouvez utiliser "IndexOf":

List<string> arr = new List<string>();
arr.Add("aaa");
arr.Add("bbb");
arr.Add("ccc");
int i = arr.IndexOf("bbb"); // RETURNS 1.
Jose Manuel Abarca Rodríguez
la source
71

EDIT: Si vous utilisez uniquement un List<>et que vous avez seulement besoin de l'index, List.FindIndexc'est en effet la meilleure approche. Je vais laisser cette réponse ici pour ceux qui ont besoin de quelque chose de différent (par exemple au-dessus de tout IEnumerable<>).

Utilisez la surcharge Selectqui prend un index dans le prédicat, donc vous transformez votre liste en une paire (index, valeur):

var pair = myList.Select((Value, Index) => new { Value, Index })
                 .Single(p => p.Value.Prop == oProp);

Ensuite:

Console.WriteLine("Index:{0}; Value: {1}", pair.Index, pair.Value);

Ou si vous ne voulez que l'index et que vous l'utilisez à plusieurs endroits, vous pouvez facilement écrire votre propre méthode d'extension qui était similaire Where, mais au lieu de renvoyer les éléments d'origine, elle a renvoyé les index de ces éléments qui correspondaient au prédicat.

Jon Skeet
la source
Il semble que tout ce qu'il veut, c'est l'indice. List <>. FindIndex (Predicate <>) est la meilleure approche. Bien que le titre de la question insinue autrement, la description du PO est assez claire, il n'a besoin que de l'index "int theThingIActuallyAmInterestedIn"
Louis Ricci
1
@LastCoder: Aha - avait raté FindIndex. Oui, je suis totalement d'accord.
Jon Skeet du
Juste pour être clair, l'approche "index / valeur -> unique" est-elle "meilleure" (qui signifie ici être plus rapide en termes de Big-O) que d'itérer manuellement deux fois? Ou le fournisseur LINQ2Objects est-il suffisamment intelligent pour optimiser une des itérations? (Je fais l'hypothèse que Select et Single en général sont des opérations O (n))
sara
1
@kai: Je pense que vous devez lire comment fonctionne LINQ, en gros. C'est trop compliqué à expliquer en détail dans un commentaire. Cependant ... ceci n'est qu'une fois sur la collection source. LINQ met en place un pipeline, qui transforme paresseusement la séquence d'entrée en une autre séquence, puis l' Single()opération parcourt cette séquence et trouve l'élément unique qui correspond au prédicat. Pour plus de détails, lisez ma série de blogs edulinq: codeblog.jonskeet.uk/category/edulinq
Jon Skeet
1
+1 J'avais besoin de cette solution. Le patron a pensé que j'étais intelligent pour une fois. On m'a conseillé de documenter soigneusement cela, car il utilisait un type anonyme et peut ne pas être clair pour le prochain codeur de la région.
Adam Wells
14

Si vous ne souhaitez pas utiliser LINQ, alors:

int index;
for (int i = 0; i < myList.Count; i++)
{
    if (myList[i].Prop == oProp)
    {
       index = i;
       break;
    }
}

de cette façon, vous répétez la liste une seule fois.

gzaxx
la source
22
@KingKing personne ne l'a dit.
Tomer W
1
Est-ce la même implémentation que Linq FindIndexpar intérêt?
Coops
2
probablement pas le même code, List a quelques optimisations soignées ici et là. mais j'ai du mal à croire qu'ils peuvent rechercher une liste non ordonnée en moins de O (n), donc je dirais qu'ils sont probablement vraiment similaires dans la pratique.
sara
6
  1. Solution simple pour trouver l'index de n'importe quelle valeur de chaîne dans la liste.

Voici le code de List Of String:

int indexOfValue = myList.FindIndex(a => a.Contains("insert value from list"));
  1. Solution simple pour trouver un index pour toute valeur entière dans la liste.

Voici le code pour la liste des nombres entiers:

    int indexOfNumber = myList.IndexOf(/*insert number from list*/);

la source
2

Voici une méthode d'extension copier / coller pour IEnumerable

public static class EnumerableExtensions
{
    /// <summary>
    /// Searches for an element that matches the conditions defined by the specified predicate,
    /// and returns the zero-based index of the first occurrence within the entire <see cref="IEnumerable{T}"/>.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list">The list.</param>
    /// <param name="predicate">The predicate.</param>
    /// <returns>
    /// The zero-based index of the first occurrence of an element that matches the conditions defined by <paramref name="predicate"/>, if found; otherwise it'll throw.
    /// </returns>
    public static int FindIndex<T>(this IEnumerable<T> list, Func<T, bool> predicate)
    {
        var idx = list.Select((value, index) => new {value, index}).Where(x => predicate(x.value)).Select(x => x.index).First();
        return idx;
    }
}

Prendre plaisir.

Snæbjørn
la source
2

Si quelqu'un se demande la Arrayversion, ça se passe comme ceci:

int i = Array.FindIndex(yourArray, x => x == itemYouWant);
Ali Bordbar
la source