17 Stimmen

Abrufen einer Sammlung von Indexwerten mit einer LINQ-Abfrage

Gibt es eine bessere Möglichkeit, dies zu tun?

string[] s = {"zero", "one", "two", "three", "four", "five"};

var x = 
s
.Select((a,i) => new {Value = a, Index = i})
.Where(b => b.Value.StartsWith("t"))
.Select(c => c.Index);

d. h. ich suche nach einer effizienteren oder eleganteren Methode, um die Positionen der Elemente zu ermitteln, die den Kriterien entsprechen.

33voto

Jon Skeet Punkte 1325502

Sie können leicht Ihre eigene Erweiterungsmethode hinzufügen:

public static IEnumerable<int> IndexesWhere<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
    int index=0;
    foreach (T element in source)
    {
        if (predicate(element))
        {
            yield return index;
        }
        index++;
    }
}

Dann verwenden Sie es mit:

string[] s = {"zero", "one", "two", "three", "four", "five"};
var x = s.IndexesWhere(t => t.StartsWith("t"));

6voto

tvanfosson Punkte 506878

Wenn Sie das Beispiel nur verwenden, um LINQ zu lernen, ignorieren Sie diesen Beitrag.


Es ist mir nicht klar, dass LINQ tatsächlich der beste Weg ist, dies zu tun. Der folgende Code scheint effizienter zu sein, da kein neuer anonymer Typ erstellt werden muss. Zugegeben, Ihr Beispiel mag konstruiert sein, und die Technik könnte in einem anderen Kontext nützlicher sein, z. B. in einer Datenstruktur, in der ein Index für einen Wert genutzt werden könnte, aber der unten stehende Code ist ziemlich einfach, verständlich (kein Nachdenken erforderlich) und wohl auch effizienter.

string[] s = {"zero", "one", "two", "three", "four", "five"};
List<int> matchingIndices = new List<int>();

for (int i = 0; i < s.Length; ++i) 
{
   if (s[i].StartWith("t"))
   {
      matchingIndices.Add(i);
   }
}

0 Stimmen

Danke für die Antwort. Ich stimme zu, dass dies effizienter wäre. Wie Sie vermutet haben, ist dies eine vereinfachte Version von etwas Komplexerem, das in diesem speziellen Fall in LINQ durchgeführt werden "muss".

2 Stimmen

Und genau dieser Code funktioniert nur, wenn Sie List statt einer beliebigen IEnumerable verwenden. Ansonsten müssten Sie foreach und eine separate lokale Variable verwenden.

5voto

Mark S. Rasmussen Punkte 33348

Scheint mir in Ordnung zu sein. Sie könnten ein paar Zeichen einsparen, indem Sie die Auswahl in ändern:

.Select((Value, Index) => new {Value, Index})

0 Stimmen

Danke - ich wusste nicht, dass man das tun kann - ich dachte, man müsste neu zuweisen.

2 Stimmen

Es handelt sich um einen "Projektionsinitialisierer", der im Grunde den letzten Unterausdruck (der ein Feld oder eine Eigenschaft sein muss) innerhalb des Ausdrucks als Namen verwendet. Sie könnten also x.GetFoo().Bar verwenden, was gleichbedeutend wäre mit Bar=x.GetFoo().Bar.

2voto

Es gibt auch eine FindIndex-Methode in der Sammlungsliste, für die Sie eine Löschmethode erstellen, die den Index aus der Sammlung zurückgeben kann. http://msdn.microsoft.com/en-us/library/x1xzf2ca.aspx .

1voto

Terrence Punkte 747

Wie wäre es damit? Es ist ähnlich wie das des ursprünglichen Posters, aber ich wähle zuerst die Indizes aus und erstelle dann eine Sammlung, die den Kriterien entspricht.

var x = s.Select((a, i) => i).Where(i => s[i].StartsWith("t"));

Dies ist ein bisschen weniger effizient als einige der anderen Antworten, da die Liste zweimal vollständig durchlaufen wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X