Suchen Sie den Index eines Werts in einem Array

113

Kann linq irgendwie verwendet werden, um den Index eines Wertes in einem Array zu finden?

Diese Schleife lokalisiert beispielsweise den Schlüsselindex innerhalb eines Arrays.

for (int i = 0; i < words.Length; i++)
{
    if (words[i].IsKey)
    {
        keyIndex = i;
    }
}
initialZero
quelle
Eigentlich wäre es auch in Ordnung, nur das Wort zu bekommen.
initialZero

Antworten:

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

Dadurch erhalten Sie tatsächlich den Integer-Index und nicht das Objekt, unabhängig davon, welche benutzerdefinierte Klasse Sie erstellt haben

sidney.andrews
quelle
1
Warum wurde dies nicht System.Linqstandardmäßig zu einer Erweiterungsmethode ? Dort ist alles andere so!
QJake
63

Für Arrays können Sie verwenden: Array.FindIndex<T>:

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

Für Listen können Sie verwenden List<T>.FindIndex:

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

Sie können auch eine generische Erweiterungsmethode schreiben, die für Folgendes funktioniert 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;
}

Und Sie können auch LINQ verwenden:

int keyIndex = words
    .Select((v, i) => new {Word = v, Index = i})
    .FirstOrDefault(x => x.Word.IsKey)?.Index ?? -1;
Paolo Moretti
quelle
2
Es gibt auch eine List (T) .FindIndex- Methode
tdc
@Paolo wie wäre es mit einer Liste, die aus Lambda generiert wird? Ich erhalte einen Prädikatenfehler.
Mihir Patel
10
int keyIndex = words.TakeWhile(w => !w.IsKey).Count();
Jonas Bötel
quelle
3
+1 aber was ist, wenn der Gegenstand nicht existiert? wir werden 0 bekommen, aber der Index ist -1
Arsen Mkrtchyan
@ArsenMkrtchyan Wenn der Artikel nicht existiert, ergibt dies Wörter. Länge
Jim Balter
@ArsenMkrtchyan Du hast geschrieben "wir werden 0 bekommen" ... das war falsch. Sie haben geschrieben "aber der Index ist -1" ... das ist auch falsch. -1 ist ein häufiger Indikator für einen Fehler, aber nicht der einzig mögliche. Jeder Wert, der nicht innerhalb von 0..words.Length-1 liegt, reicht aus.
Jim Balter
1
@ JimBalter, ich meine, wenn das Element nicht existiert, gibt der Ausdruck 0 zurück. Was ist daran falsch? Ich stimme zu, dass -1 ein allgemeiner Indikator ist, stimme jedoch zu, dass es offensichtlich ist, dass 99% der Fälle -1 der erwartete Wert ist, wenn der Artikel nicht vorhanden ist. Mindestens 0 ist falsch, wenn der Artikel nicht vorhanden ist
Arsen Mkrtchyan
7

Wenn Sie das Wort finden möchten, können Sie es verwenden

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

Dies gibt Ihnen das erste Element, für das IsKey wahr ist (wenn es möglicherweise kein Element gibt, möchten Sie es möglicherweise verwenden .FirstOrDefault()

Um sowohl das Element als auch den Index zu erhalten, können Sie verwenden

KeyValuePair<WordType, int> word = words.Select((item, index) => new KeyValuePair<WordType, int>(item, index)).Where(item => item.Key.IsKey).First();
Grizzly
quelle
linq ist verrückt. Ich fand Java-Generika verrückt. Trotzdem danke für all die Hilfe.
initialZero
Wird das Umwandeln des Rückgabewerts akzeptiert oder gibt es eine Möglichkeit, die Art des Wortes zu definieren?
initialZero
ok, ich habe mir das ausgedacht. DecodedMessageWord keyWord = words.Where (x => x.IsKey == true) .First <DecodedMessageWord> ();
initialZero
5
@initialZero überprüfe die Überladungen auf First, es braucht ein Prädikat, du brauchst das nicht Where.
Yuriy Faktorovich
3

Versuche dies...

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

quelle
2
Dies scheint eine sehr schwache Lösung im Vergleich zu den Antworten von Grizzly und Masenkablast zu sein. masenkablast beantwortet die ursprüngliche Frage und Grizzly bietet eine bessere Lösung, um das Wort zu finden, da sein letztes "var" das eigentliche Wort ist und keine IEnumerable <TSource>, die 1 Wort enthält.
James
2

Ich habe gerade meine Implementierung der IndexWhere () - Erweiterungsmethode (mit Unit-Tests) veröffentlicht:

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

Anwendungsbeispiel:

int index = myList.IndexWhere(item => item.Something == someOtherThing);
Joelsand
quelle
Ich würde diese Bibliothek nicht verwenden, sie implementiert diese Methoden nicht richtig. Es ignoriert die Entsorgung.
Yuriy Faktorovich
1

Diese Lösung hat mir von msdn microsoft mehr geholfen :

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

queryist Ihre toList()Anfrage.

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