Wie erhalte ich den Index eines Elements in einer Liste in einem einzigen Schritt?


193

Wie kann ich den Index eines Elements in einer Liste finden, ohne ihn zu durchlaufen?

Derzeit sieht das nicht besonders gut aus. Durchsuchen Sie die Liste zweimal nach demselben Element, um den Index zu erhalten:

var oProp = something;

int theThingIActuallyAmInterestedIn = myList.IndexOf(myList.Single(i => i.Prop == oProp));

Antworten:


434

Wie wäre es mit der List.FindIndex-Methode :

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

Diese Methode führt eine lineare Suche durch. Daher ist diese Methode eine O (n) -Operation, wobei n Count ist.

Wenn das Element nicht gefunden wird, wird -1 zurückgegeben


2
Wie wäre es int index?
Dylan Czenski

2
@ DylanChensky er hat JS zu viel
codiert

9
Als Referenz, wenn der Artikel nicht gefunden wird; es wird -1
Daniel Filipe

102

Für einfache Typen können Sie "IndexOf" verwenden:

List<string> arr = new List<string>();
arr.Add("aaa");
arr.Add("bbb");
arr.Add("ccc");
int i = arr.IndexOf("bbb"); // RETURNS 1.

71

BEARBEITEN: Wenn Sie nur a verwenden List<>und nur den Index benötigen, List.FindIndexist dies in der Tat der beste Ansatz. Ich werde diese Antwort hier für diejenigen hinterlassen, die etwas anderes brauchen (z. B. obendrein IEnumerable<>).

Verwenden Sie die Überladung, für Selectdie ein Index im Prädikat verwendet wird, damit Sie Ihre Liste in ein (Index-, Wert-) Paar umwandeln:

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

Dann:

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

Oder wenn Sie nur den Index möchten und diesen an mehreren Stellen verwenden, können Sie leicht eine eigene Erweiterungsmethode schreiben Where, die der folgenden entspricht. Statt jedoch die ursprünglichen Elemente zurückzugeben, werden die Indizes der Elemente zurückgegeben, die dem Prädikat entsprechen.


Anscheinend will er nur den Index. List <>. FindIndex (Predicate <>) ist der beste Ansatz. Obwohl der Fragentitel anders andeuten würde, ist die Beschreibung des OP ziemlich klar, dass er nur den Index "int theThingIActuallyAmInterestedIn" benötigt
Louis Ricci

1
@ LastCoder: Aha - hatte FindIndex verpasst. Ja, ich stimme vollkommen zu.
Jon Skeet

Ist der "Index / Wert -> Einzel" -Ansatz "besser" (hier bedeutet dies, dass er in Bezug auf Big-O schneller ist) als zweimal manuell zu iterieren? Oder ist der LINQ2Objects-Anbieter intelligent genug, um eine der Iterationen zu optimieren? (Ich gehe davon aus, dass sowohl Select als auch Single im Allgemeinen O (n) -Operationen sind)
Sara

1
@kai: Ich denke, Sie müssen sich im Grunde darüber informieren, wie LINQ funktioniert. Es ist zu kompliziert, dies in einem Kommentar ausführlich zu erklären. Dies wird jedoch nur einmal über die Quellensammlung wiederholt. LINQ richtet eine Pipeline ein, die die Eingabesequenz träge in eine andere Sequenz umwandelt. Anschließend Single()durchläuft die Operation diese Sequenz und findet das einzelne Element, das dem Prädikat entspricht. Weitere Informationen finden Sie in meiner Edulinq-Blogserie: codeblog.jonskeet.uk/category/edulinq
Jon Skeet

1
+1 Ich brauchte diese Lösung. Boss dachte, ich wäre einmal schlau. Es wurde mir empfohlen, dies sorgfältig zu dokumentieren, da es sich um einen anonymen Typ handelt und für den nächsten Codierer in der Umgebung möglicherweise nicht klar ist.
Adam Wells

14

Wenn Sie LINQ nicht verwenden möchten, gehen Sie wie folgt vor:

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

Auf diese Weise iterieren Sie die Liste nur einmal.


22
@KingKing niemand sagte es ist.
Tomer W

1
Ist dies die gleiche Implementierung wie Linq FindIndexaus Interesse?
Coops

2
wahrscheinlich nicht der gleiche Code, List hat hier und da einige nette Optimierungen. aber es fällt mir schwer zu glauben, dass sie eine ungeordnete Liste in weniger als O (n) durchsuchen können, daher würde ich sagen, dass sie sich in der Praxis wahrscheinlich sehr ähnlich sind.
Sara

6
  1. Einfache Lösung, um einen Index für einen beliebigen Zeichenfolgenwert in der Liste zu finden.

Hier ist der Code für die Liste der Zeichenfolgen:

int indexOfValue = myList.FindIndex(a => a.Contains("insert value from list"));
  1. Einfache Lösung, um einen Index für einen beliebigen Integer-Wert in der Liste zu finden.

Hier ist der Code für die Liste der Ganzzahlen:

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

2

Hier ist eine kopier- / einfügefähige Erweiterungsmethode für 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;
    }
}

Genießen.


2

Wenn sich jemand für die ArrayVersion wundert , geht es so:

int i = Array.FindIndex(yourArray, x => x == itemYouWant);
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.