È possibile avviare l'iterazione da un elemento diverso dal primo utilizzando foreach?


89

Sto pensando di implementare IEnumerable per la mia raccolta personalizzata (un albero) in modo da poter utilizzare foreach per attraversare il mio albero. Tuttavia, per quanto ne so foreach parte sempre dal primo elemento della collezione. Vorrei scegliere da quale elemento inizia per ogni. È possibile in qualche modo cambiare l'elemento da cui inizia foreach?



Se non parti dal primo elemento, come definisci il comportamento dell'iteratore? Cosa succede quando arriva alla fine della sequenza? Quindi torna al primo elemento e ripete gli elementi rimanenti?
Dan J

Il commento di @ ChaosPandion è dove stavo andando con quelle domande. :)
Dan J

Risposte:


165

Sì. Fare quanto segue:

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

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

Skipè una funzione IEnumerable che ignora quanti ne specifichi a partire dall'indice corrente. D'altra parte, se volessi usare solo i primi tre, useresti .Take:

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

Questi possono anche essere accoppiati insieme, quindi se volessi solo i 4-6 elementi potresti fare:

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

Ottima scelta. Completamento automatico WTB (gahh non ricorda il vero nome) in
stackoverflow

Questo effettivamente salta o crea solo una copia? IE sarebbero questi due diversi: 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

È più semplice utilizzare il Skipmetodo in LINQ to Objects per questo, per saltare un determinato numero di elementi:

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

Ovviamente basta cambiare 1 per qualsiasi altro valore per saltare un diverso numero di elementi ...

Allo stesso modo è possibile utilizzare Takeper limitare il numero di elementi restituiti.

Si può leggere di più su entrambi questi (e il relativo SkipWhilee TakeWhilemetodi) nella mia Edulinq serie di blog .


Jon, questo non corre il rischio di un'eccezione se "sequenza" è nulla?
WEFX

@WEFX: Beh, non abbiamo idea se sequencepossa essere legittimamente nullo meno. Presumibilmente l'OP può gestirlo da solo - non fa davvero parte della domanda ...
Jon Skeet

5

Puoi usare Enumerable.Skip per saltare alcuni elementi e farlo iniziare da lì.

Per esempio:

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

Tuttavia, se stai scrivendo un albero, potresti voler fornire un membro sull'elemento albero stesso che restituirà un nuovo IEnumerable<T>che verrà enumerato da lì in basso. Ciò, potenzialmente, sarebbe più utile a lungo termine.


Qualcosa di simile IEnumerable<T> SubTree(rootIndex)? Ottima scelta!
Dan J

Grazie per la risposta, skip sembra promettente, leggendo le informazioni MSDN su skip sono arrivato alla conclusione che forse è possibile scrivere un metodo StartFrom (questo albero IEnumerable <MyTree>, elemento MyTreeElement) che sarebbe un metodo di estensione per IEnumerable <MyTree> che restituirebbe IEnumerable <MyTreeElement> da cui dovrei iniziare l'iterazione. Allora forse potrei usare questo metodo come foreach (var element in tree.StartFrom (someElement))).
inferno

@inferno: Sì, potresti farlo facilmente. Tuttavia, aggiungerei semplicemente un metodo / proprietà a MyTreeElement che fosse più simile a:, IEnumerable<MyTreeElement> Childrenquindi potresti semplicemente fare: foreach(var item in someElement.Children)- molto più chiaro rispetto all'utilizzo dei metodi di estensione IMO.
Reed Copsey

-1

Foreachitererà sulla tua raccolta nel modo definito dalla tua implementazione di IEnumerable. Quindi, sebbene tu possa saltare gli elementi (come suggerito sopra), tecnicamente stai ancora iterando sugli elementi nello stesso ordine.

Non sei sicuro di cosa stai cercando di ottenere, ma la tua classe potrebbe avere più IEnumerableproprietà, ognuna delle quali enumera gli elementi in un ordine specifico.


-1

Se vuoi saltare la lettura delle righe in a DataGridView, prova questo

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

Se vuoi copiare i contenuti di uno DataGridViewin un altro saltando le righe, prova questo,

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

questo copia i contenuti da uno DataGridViewall'altro saltando 3 righe.


Questo non risponde alla domanda che è stata posta: la domanda non menziona DataGridViewaffatto (o anche un framework dell'interfaccia utente).
NightOwl888

@ NightOwl888 è stata data una risposta perché la domanda riguardava il saltare alcune iterazioni e l'iterazione successiva nel ciclo foreach. Nel mio esempio ho appena usato Skip () per applicare su DataGridView.
Juned Khan Momin,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.