Rechercher l'index d'une valeur dans un tableau

113

Linq peut-il être utilisé d'une manière ou d'une autre pour trouver l'index d'une valeur dans un tableau?

Par exemple, cette boucle localise l'index de clé dans un tableau.

for (int i = 0; i < words.Length; i++)
{
    if (words[i].IsKey)
    {
        keyIndex = i;
    }
}
initialZero
la source
En fait, le simple fait de recevoir le mot serait aussi bien.
initialZero

Réponses:

183
int keyIndex = Array.FindIndex(words, w => w.IsKey);

Cela vous donne en fait l'index entier et non l'objet, quelle que soit la classe personnalisée que vous avez créée

sidney.andrews
la source
1
Pourquoi cela n'a-t-il pas été transformé en méthode d'extension System.Linqpar défaut? C'est là que tout le reste est là!
qJake
63

Pour les tableaux, vous pouvez utiliser Array.FindIndex<T>::

int keyIndex = Array.FindIndex(words, w => w.IsKey);

Pour les listes, vous pouvez utiliser List<T>.FindIndex:

int keyIndex = words.FindIndex(w => w.IsKey);

Vous pouvez également écrire une méthode d'extension générique qui fonctionne pour tout Enumerable<T>:

///<summary>Finds the index of the first item matching an expression in an enumerable.</summary>
///<param name="items">The enumerable to search.</param>
///<param name="predicate">The expression to test the items against.</param>
///<returns>The index of the first matching item, or -1 if no items match.</returns>
public static int FindIndex<T>(this IEnumerable<T> items, Func<T, bool> predicate) {
    if (items == null) throw new ArgumentNullException("items");
    if (predicate == null) throw new ArgumentNullException("predicate");

    int retVal = 0;
    foreach (var item in items) {
        if (predicate(item)) return retVal;
        retVal++;
    }
    return -1;
}

Et vous pouvez également utiliser LINQ:

int keyIndex = words
    .Select((v, i) => new {Word = v, Index = i})
    .FirstOrDefault(x => x.Word.IsKey)?.Index ?? -1;
Paolo Moretti
la source
2
Il existe également une méthode List (T) .FindIndex
tdc
@Paolo que diriez-vous d'une liste générée à partir de Lambda? J'obtiens une erreur de prédicat.
Mihir Patel
10
int keyIndex = words.TakeWhile(w => !w.IsKey).Count();
Jonas Bötel
la source
3
+1 mais, et si l'élément n'existe pas? nous obtiendrons 0, mais l'indice est -1
Arsen Mkrtchyan
@ArsenMkrtchyan Si l'élément n'existe pas, cela donne des mots.Longueur
Jim Balter
@ArsenMkrtchyan Vous avez écrit "nous obtiendrons 0" ... c'était faux. Vous avez écrit "mais l'index est -1" ... c'est également faux. -1 est un indicateur courant d'échec, mais ce n'est pas le seul possible. Toute valeur non comprise entre 0..words.Length-1 fera l'affaire.
Jim Balter
1
@JimBalter, je veux dire si l'élément n'existe pas, l'expression retournera 0, qu'est-ce qui ne va pas? Je suis d'accord que -1 est un indicateur commun, mais je conviens qu'il est évident que 99% des cas -1 est la valeur attendue lorsque l'élément n'existe pas. au moins 0 est faux lorsque l'élément n'existe pas
Arsen Mkrtchyan
7

Si vous voulez trouver le mot que vous pouvez utiliser

var word = words.Where(item => item.IsKey).First();

Cela vous donne le premier élément pour lequel IsKey est vrai (s'il n'y en a pas, vous pouvez utiliser .FirstOrDefault()

Pour obtenir à la fois l'élément et l'index, vous pouvez utiliser

KeyValuePair<WordType, int> word = words.Select((item, index) => new KeyValuePair<WordType, int>(item, index)).Where(item => item.Key.IsKey).First();
Grizzly
la source
linq est fou. Je pensais que les génériques Java étaient fous. Quoi qu'il en soit, merci pour toute l'aide.
initialZero
La conversion de la valeur de retour est-elle une pratique acceptée ou existe-t-il un moyen de définir le type de mot?
initialZero
ok, je suis venu avec ça. DecodedMessageWord keyWord = words.Where (x => x.IsKey == true) .First <DecodedMessageWord> ();
initialZero
5
@initialZero vérifie les surcharges pour First, il faut un prédicat, vous n'avez pas besoin du Where.
Yuriy Faktorovich
3

Essaye ça...

var key = words.Where(x => x.IsKey == true);

la source
2
Cela semble être une solution très faible par rapport aux réponses de Grizzly et masenkablast. masenkablast répond à la question originale et Grizzly donne une meilleure solution pour trouver le mot, car son "var" final sera le mot réel et non un IEnumerable <TSource> qui contient 1 mot.
James
2

Je viens de publier mon implémentation de la méthode d'extension IndexWhere () (avec des tests unitaires):

http://snipplr.com/view/53625/linq-index-of-item--indexwhere/

Exemple d'utilisation:

int index = myList.IndexWhere(item => item.Something == someOtherThing);
Joelsand
la source
Je n'utiliserais pas cette bibliothèque, elle n'implémente pas correctement ces méthodes. Il ignore l'élimination.
Yuriy Faktorovich le
1

Cette solution m'a aidé davantage, de msdn microsoft :

var result =  query.AsEnumerable().Select((x, index) =>
              new { index,x.Id,x.FirstName});

queryest votre toList()requête.

Roshna Omer
la source
0
int index = -1;
index = words.Any (word => { index++; return word.IsKey; }) ? index : -1;
Marcel Valdez Orozco
la source