Jak pominąć iterację pętli „foreach”?

324

W Perlu mogę pominąć iterację foreach (lub dowolnej pętli) za pomocą next;polecenia.

Czy istnieje sposób na pominięcie iteracji i przejście do następnej pętli w C #?

 foreach (int number in numbers)
 {
     if (number < 0)
     {
         // What goes here to skip over the loop?
     }

     // otherwise process number
 }
Brian
źródło
Powiadomienie użytkownika o złych danych wejściowych jest równie ważne, jak pominięcie go!
Przydatne,

Odpowiedzi:

664

Chcesz:

foreach (int number in numbers) //   <--- go back to here --------+
{                               //                                |
    if (number < 0)             //                                |
    {                           //                                |
        continue;   // Skip the remainder of this iteration. -----+
    }

    // do work
}

Oto więcej o tym continuesłowie kluczowym .


Aktualizacja: W odpowiedzi na dalsze pytanie Briana w komentarzach:

Czy możesz wyjaśnić, co bym zrobił, gdybym zagnieździł pętle i chciałem pominąć iterację jednego z rozszerzonych?

for (int[] numbers in numberarrays) {
  for (int number in numbers) { // What to do if I want to
                                // jump the (numbers/numberarrays)?
  }
}

continueZawsze odnosi się do najbliższego zakresu okalającego, więc nie można go używać, aby wyrwać się z pętli peryferyjnych. Jeśli pojawi się taki stan, musisz zrobić coś bardziej skomplikowanego w zależności od tego, czego dokładnie chcesz, na przykład breakz pętli wewnętrznej, a następnie continuez pętli zewnętrznej. Zobacz tutaj dokumentację breaksłowa kluczowego . breakC # Hasło jest podobna do Perl lasthasła.

Rozważ też skorzystanie z sugestii Dustina, aby po prostu odfiltrować wartości, których nie chcesz wcześniej przetwarzać:

foreach (var basket in baskets.Where(b => b.IsOpen())) {
  foreach (var fruit in basket.Where(f => f.IsTasty())) {
    cuteAnimal.Eat(fruit); // Om nom nom. You don't need to break/continue
                           // since all the fruits that reach this point are
                           // in available baskets and tasty.
  }
}
John Feminella
źródło
Czy możesz wyjaśnić, co bym zrobił, gdybym zagnieździł pętle i chciałem pominąć iterację jednego z rozszerzonych? np .: for (int [] numbers in numberarrays) {for (int number in numbers) {// Co zrobić, jeśli chcesz przeskoczyć (numbers / numberarrays)}}
Brian
C # gotojest w rzeczywistości przydatne w sytuacji, o którą pyta @Brian. Dodaj etykietę, na przykład nextArray:na dole zewnętrznej pętli, a następnie, goto nextArray;gdy chcesz do niej przejść.
Jacob Krall
55

Innym podejściem jest filtrowanie przy użyciu LINQ przed wykonaniem pętli:

foreach ( int number in numbers.Where(n => n >= 0) )
{
    // process number
}
Dustin Campbell
źródło
2
+1. Chociaż nie jest to bezpośrednia odpowiedź na pytanie, w praktyce prawdopodobnie wolałbym to rozwiązanie od tego, które zaproponowałem. Korzystanie z LINQ wydaje się być dobrym ogólnym przypadkiem użycia do filtrowania wartości pętli, których nie chcesz przetwarzać.
John Feminella,
3
Czy to jest po prostu bardziej uporządkowane, czy może rzeczywiście będzie szybsze, że jest mniej do przepowiadania? Zgaduję, że LINQ jest znacznie zoptymalizowany, ale sekcja LINQ będzie musiała w pewnym momencie przewidywać, więc teoretycznie, jeśli zestaw danych jest duży, a wynikowy podzbiór „filtrowany” jest prawie tak duży, to będzie wolniej, ponieważ foreach musi się zdarzyć dwa razy? Więc może to zależy od oczekiwanego wynikowego pod-zestawu danych?
Coops
25

Możesz także przerzucić test if:


foreach ( int number in numbers )
{
     if ( number >= 0 )
     {
        //process number
     }
 }
crashmstr
źródło
:) Dzięki! Podaję prosty przykład, ponieważ na początku pętli istniały pewne kryteria, które nie wymagałyby przetworzenia, a inne to błędy, które należało wychwycić.
Brian
4
Jedna odpowiedź oparta na LINQ jest ładna i elegancka, ale użycie instrukcji if nie jest złe.
crashmstr
21
foreach ( int number in numbers )
{
    if ( number < 0 )
    {
        continue;
    }

    //otherwise process number
}
Tamas Czinege
źródło
16

Możesz użyć continuewyciągu.

Na przykład:

foreach(int number in numbers)
{
    if(number < 0)
    {
        continue;
    }
}
Kev
źródło
16

Innym podejściem wykorzystującym linq jest:

foreach ( int number in numbers.Skip(1))
{   
    // process number  
}

Jeśli chcesz pominąć pierwszy z wielu elementów.

Lub użyj, .SkipWherejeśli chcesz określić warunek pominięcia.

Edmund Covington
źródło
Jest to najprostszy (choć może logika jest taka sama) sposób na zrobienie tego - teraz, gdy masz dostęp do Linq. Chociaż powinieneś upewnić się, że .Skip jest wywoływany tylko raz ze względu na wydajność. (Tak, widzę teraz, że nie jest to bezpośrednia odpowiedź na pytanie OP, chociaż jest cennym dodatkiem do tej listy odpowiedzi). +1
B Charles H
8

Użyj instrukcji Continue:

foreach(object number in mycollection) {
     if( number < 0 ) {
         continue;
     }
  }
Drawh
źródło
3
Nie rozumiem, dlaczego jest to głosowane, to źle, ponieważ zapętla on „o”, a nie „numer”
Fortune,
Zgadzam się, może to jest kopia / wklej z poprzednich odpowiedzi? Koncepcyjnie cenny, ponieważ jest to foreach, ale proszę upewnić się, że zmienne są spójne.
Antonio Ciolino
0

Najłatwiej to zrobić, jak poniżej:

//Skip First Iteration

foreach ( int number in numbers.Skip(1))

//Skip any other like 5th iteration

foreach ( int number in numbers.Skip(5))
Kashif
źródło