Czy można rozpocząć iterację od elementu innego niż pierwszy przy użyciu foreach?

87

Zastanawiam się nad zaimplementowaniem IEnumerable dla mojej kolekcji niestandardowej (drzewa), aby móc używać foreach do przechodzenia po moim drzewie. Jednak z tego co wiem, zawsze zaczyna się od pierwszego elementu kolekcji. Chciałbym wybrać, od którego elementu każdy zaczyna się. Czy da się jakoś zmienić element, od którego każdy zaczyna?

piekło
źródło
1
Przestrzegałbym
Jeśli nie zaczniesz od pierwszego elementu, jak zdefiniujesz zachowanie iteratora? Co się stanie, gdy dojdzie do końca sekwencji? Czy następnie wraca do pierwszego elementu i iteruje po pozostałych elementach?
Dan J
Komentarz @ ChaosPandion jest miejscem, do którego zmierzałem z tymi pytaniami. :)
Dan J

Odpowiedzi:

163

Tak. Wykonaj następujące czynności:

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

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

Skipjest funkcją IEnumerable, która pomija dowolną liczbę określoną, zaczynając od bieżącego indeksu. Z drugiej strony, gdybyś chciał użyć tylko pierwszych trzech, użyłbyś .Take:

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

Można je nawet łączyć ze sobą, więc jeśli chcesz tylko 4-6 elementów, które możesz zrobić:

foreach (string curString in myCollection.Skip(3).Take(3))
MoarCodePlz
źródło
Dobra decyzja. Autouzupełnianie WTB (gahh nie może sobie przypomnieć jego prawdziwej nazwy) w stackoverflow;)
MoarCodePlz
Czy to rzeczywiście pomija, czy po prostu tworzy kopię? IE czy te dwa byłyby inne: 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

Najłatwiej jest użyć do tego Skipmetody w LINQ to Objects, aby pominąć określoną liczbę elementów:

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

Oczywiście po prostu zmień 1 dla dowolnej innej wartości, aby pominąć inną liczbę elementów ...

Podobnie możesz użyć, Takeaby ograniczyć liczbę zwracanych elementów.

Możesz przeczytać więcej na temat obu tych metod (oraz powiązanych SkipWhilei TakeWhilemetod) w mojej serii blogów Edulinq .

Jon Skeet
źródło
Jon, czy nie grozi to wyjątkiem, jeśli „sekwencja” ma wartość Null?
WEFX
@WEFX: Cóż, nie mamy pojęcia, czy sequencemoże to być uzasadnione, nullczy nie. Prawdopodobnie OP sam sobie z tym poradzi - to nie jest tak naprawdę część pytania ...
Jon Skeet
5

Możesz użyć Enumerable.Skip, aby pominąć niektóre elementy i zacząć od tego.

Na przykład:

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

Jednakże, jeśli piszesz drzewo, możesz chcieć zapewnić element członkowski w samym elemencie drzewa, który zwróci nowy, IEnumerable<T>który wyliczy stamtąd. Potencjalnie byłoby to bardziej przydatne w dłuższej perspektywie.

Reed Copsey
źródło
Coś jak IEnumerable<T> SubTree(rootIndex)? Dobra decyzja!
Dan J
Dzięki za odpowiedź, skip wygląda obiecująco, czytając informacje MSDN o skip Doszedłem do wniosku, że być może da się napisać metodę StartFrom (to drzewo IEnumerable <MyTree>, element MyTreeElement), która byłaby metodą rozszerzającą dla IEnumerable <MyTree>, która zwróci IEnumerable <MyTreeElement>, od którego powinienem rozpocząć iterację. Wtedy może mógłbym użyć tej metody jako foreach (element var w tree.StartFrom (someElement))).
piekło
@inferno: Tak, możesz to łatwo zrobić. Jednak dodałbym po prostu metodę / właściwość do MyTreeElement, która byłaby bardziej podobna do:, IEnumerable<MyTreeElement> Childrenwięc możesz po prostu zrobić: foreach(var item in someElement.Children)- znacznie bardziej przejrzyste niż użycie metod rozszerzających IMO.
Reed Copsey
-1

Foreachbędzie iterować Twoją kolekcję w sposób zdefiniowany przez Twoją implementację IEnumerable. Tak więc, chociaż możesz pomijać elementy (jak zasugerowano powyżej), nadal technicznie iterujesz po elementach w tej samej kolejności.

Nie jestem pewien, co próbujesz osiągnąć, ale Twoja klasa może mieć wiele IEnumerablewłaściwości, z których każda wylicza elementy w określonej kolejności.

Obrabować
źródło
-1

Jeśli chcesz pominąć czytanie wierszy w a DataGridView, spróbuj tego

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

Jeśli chcesz skopiować zawartość jednej DataGridViewdo drugiej, pomijając wiersze, spróbuj tego,

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;
}

kopiuje zawartość z jednego DataGridViewdo drugiego pomijając 3 wiersze.

Juned Khan Momin
źródło
To nie odpowiada na zadane pytanie - pytanie w ogóle nie wspomina DataGridView(ani nawet o frameworku interfejsu użytkownika).
NightOwl888
@ NightOwl888 otrzymałem odpowiedź, ponieważ pytanie dotyczyło pominięcia niektórych iteracji i iteracji po nich w pętli foreach. W moim przykładzie właśnie użyłem Skip (), aby zastosować na DataGridView.
Juned Khan Momin