Ist es möglich, mit foreach von einem anderen Element als dem ersten zu iterieren?

86

Ich denke darüber nach, IEnumerable für meine benutzerdefinierte Sammlung (einen Baum) zu implementieren, damit ich foreach verwenden kann, um meinen Baum zu durchlaufen. Soweit ich weiß, beginnt foreach jedoch immer mit dem ersten Element der Sammlung. Ich möchte auswählen, aus welchem ​​Element jeder beginnt. Ist es möglich, das Element, von dem foreach ausgeht, irgendwie zu ändern?

Inferno
quelle
1
Ich würde dem Prinzip des geringsten Erstaunens folgen: en.wikipedia.org/wiki/Principle_of_least_astonishment
ChaosPandion
Wenn Sie nicht mit dem ersten Element beginnen, wie definieren Sie das Verhalten des Iterators? Was passiert, wenn das Ende der Sequenz erreicht ist? Geht es dann zurück zum ersten Element und iteriert es über die verbleibenden Elemente?
Dan J
@ ChaosPandions Kommentar ist, wohin ich mit diesen Fragen gegangen bin. :)
Dan J

Antworten:

162

Ja. Mach Folgendes:

Collection<string> myCollection = new Collection<string>;

foreach (string curString in myCollection.Skip(3))
    //Dostuff

Skipist eine IEnumerable-Funktion, die alle angegebenen Werte überspringt, beginnend mit dem aktuellen Index. Wenn Sie jedoch nur die ersten drei verwenden möchten, würden Sie Folgendes verwenden .Take:

foreach (string curString in myCollection.Take(3))

Diese können sogar miteinander gepaart werden. Wenn Sie also nur die 4-6 Elemente möchten, können Sie Folgendes tun:

foreach (string curString in myCollection.Skip(3).Take(3))
MoarCodePlz
quelle
Guter Anruf. WTB Auto-Vervollständigung (Gahh kann sich nicht an den richtigen Namen erinnern) in Stackoverflow;)
MoarCodePlz
Überspringt dies tatsächlich oder erstellt es nur eine Kopie? IE würden diese zwei unterschiedlich sein: foreach(List<string> row in rows.skip(1)){ row[0] = "newInfo"; } vs for(int i=1; i<rows.Count;i++){ List<string> row = rows[i]; row[0] = "newStuff"; }
TigerBear
25

Es ist am einfachsten, die SkipMethode in LINQ to Objects zu verwenden, um eine bestimmte Anzahl von Elementen zu überspringen:

foreach (var value in sequence.Skip(1)) // Skips just one value
{
    ...
}

Ändern Sie einfach 1 für einen anderen Wert, um eine andere Anzahl von Elementen zu überspringen ...

Ebenso können Sie Takedie Anzahl der zurückgegebenen Elemente begrenzen.

Sie können mehr über diese beiden lesen (und die damit verbundene SkipWhileund TakeWhileMethoden) in meiner Edulinq Blog - Serie .

Jon Skeet
quelle
Jon, läuft dies nicht Gefahr einer Ausnahme, wenn "Sequenz" Null ist?
WEFX
@WEFX: Nun, wir haben keine Ahnung, ob sequencedies legitim sein kann nulloder nicht. Vermutlich kann das OP das selbst erledigen - das ist nicht wirklich Teil der Frage ...
Jon Skeet
5

Mit Enumerable.Skip können Sie einige Elemente überspringen und dort starten.

Beispielsweise:

foreach(item in theTree.Skip(9))  // Skips the first 9 items
{
    // Do something

Wenn Sie jedoch einen Baum schreiben, möchten Sie möglicherweise ein Mitglied für das Baumelement selbst bereitstellen, das ein neues IEnumerable<T>zurückgibt, das von dort unten aufgelistet wird. Dies wäre möglicherweise auf lange Sicht nützlicher.

Reed Copsey
quelle
So etwas wie IEnumerable<T> SubTree(rootIndex)? Guter Anruf!
Dan J
Vielen Dank für die Antwort. Das Überspringen sieht vielversprechend aus. Beim Lesen der MSDN-Informationen zum Überspringen bin ich zu dem Schluss gekommen, dass es möglicherweise möglich ist, eine Methode StartFrom (dieses IEnumerable <MyTree> -Baum, MyTreeElement-Element) zu schreiben, die eine Erweiterungsmethode für IEnumerable <MyTree> wäre würde IEnumerable <MyTreeElement> zurückgeben, von dem aus ich mit der Iteration beginnen sollte. Dann könnte ich diese Methode vielleicht als foreach verwenden (var-Element in tree.StartFrom (someElement)).
Inferno
@inferno: Ja, das kannst du leicht machen. Ich würde MyTreeElement jedoch nur eine Methode / Eigenschaft hinzufügen, die eher wie folgt lautet: IEnumerable<MyTreeElement> ChildrenSie könnten also einfach Folgendes tun: foreach(var item in someElement.Children)- viel klarer als die Verwendung von IMO-Erweiterungsmethoden.
Reed Copsey
-1

Foreachwird Ihre Sammlung in der durch Ihre Implementierung von definierten Weise durchlaufen IEnumerable. Obwohl Sie Elemente überspringen können (wie oben vorgeschlagen), durchlaufen Sie die Elemente technisch immer noch in derselben Reihenfolge.

Sie sind sich nicht sicher, was Sie erreichen möchten, aber Ihre Klasse kann mehrere IEnumerableEigenschaften haben, von denen jede die Elemente in einer bestimmten Reihenfolge auflistet.

rauben
quelle
-1

Wenn Sie das Lesen von Zeilen in a überspringen möchten DataGridView, versuchen Sie dies

foreach (DataGridViewRow row in dataGridView1.Rows.Cast<DataGridViewRow().Skip(3))

Wenn Sie den Inhalt einer DataGridViewZeile in eine andere überspringen möchten , versuchen Sie Folgendes:

foreach (DataGridViewRow row in dataGridView1.Rows.Cast<DataGridViewRow>().Skip(3))
{
    foreach (DataGridViewCell cell in row.Cells)
    {
        string value = cell.Value.ToString();
        dataGridView2.Rows[i].Cells[j].Value = cell.Value.ToString();
        j++;
    }
    i++;
    j = 0;
}

Dadurch wird der Inhalt von einer DataGridViewzur anderen kopiert , wobei 3 Zeilen übersprungen werden.

Juned Khan Momin
quelle
Dies beantwortet nicht die gestellte Frage - die Frage wird überhaupt nicht erwähnt DataGridView(oder sogar ein UI-Framework).
NightOwl888
@ NightOwl888 Dies wurde beantwortet, da es um das Überspringen einiger Iterationen und das anschließende Iterieren in jeder Schleife ging. In meinem Beispiel habe ich gerade Skip () verwendet, um auf DataGridView anzuwenden.
Juned Khan Momin