¿Es posible comenzar a iterar desde un elemento que no sea el primero usando foreach?


86

Estoy pensando en implementar IEnumerable para mi colección personalizada (un árbol) para poder usar foreach para atravesar mi árbol. Sin embargo, hasta donde yo sé, foreach siempre comienza desde el primer elemento de la colección. Me gustaría elegir desde qué elemento comienza cada uno. ¿Es posible cambiar de alguna manera el elemento desde el que comienza foreach?


1
Seguiría el principio del menor asombro: en.wikipedia.org/wiki/Principle_of_least_astonishment
ChaosPandion

Si no comienza desde el primer elemento, ¿cómo define el comportamiento del iterador? ¿Qué sucede cuando llega al final de la secuencia? ¿Luego vuelve al primer elemento e itera sobre los elementos restantes?
Dan J

El comentario de @ ChaosPandion es a donde iba con esas preguntas. :)
Dan J

Respuestas:


162

Si. Haz lo siguiente:

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

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

Skipes una función IEnumerable que omite la cantidad que especifique a partir del índice actual. Por otro lado, si quisiera usar solo los primeros tres, usaría .Take:

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

Estos incluso se pueden emparejar, por lo que si solo desea los 4-6 elementos, puede hacer:

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

Buena llamada. WTB autocompletado (gahh no puede recordar el nombre real) en stackoverflow;)
MoarCodePlz

¿Esto realmente se salta o simplemente crea una copia? IE, ¿serían estos dos diferentes: 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 más fácil usar el Skipmétodo en LINQ to Objects para esto, para omitir una cantidad determinada de elementos:

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

Obviamente, solo cambie 1 por cualquier otro valor para omitir un número diferente de elementos ...

Del mismo modo, puede utilizar Takepara limitar el número de elementos que se devuelven.

Puede leer más sobre ambos (y el relacionado SkipWhiley TakeWhilemétodos) en mi blog, Edulinq serie .


Jon, ¿esto no corre el riesgo de una excepción si "secuencia" es nula?
WEFX

@WEFX: Bueno, no tenemos idea de si sequencepuede ser legítimamente nullo no. Presumiblemente, el OP puede manejar eso por sí mismo, no es realmente parte de la pregunta ...
Jon Skeet

5

Puede usar Enumerable.Skip para omitir algunos elementos y hacer que comience allí.

Por ejemplo:

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

Sin embargo, si está escribiendo un árbol, es posible que desee proporcionar un miembro en el elemento del árbol en sí que devolverá un nuevo IEnumerable<T>que se enumerará desde allí hacia abajo. Esto, potencialmente, sería más útil a largo plazo.


Algo como IEnumerable<T> SubTree(rootIndex)? ¡Buena llamada!
Dan J

Gracias por la respuesta, skip parece prometedor, leyendo la información de MSDN sobre skip llegué a la conclusión de que tal vez sea posible escribir un método StartFrom (este árbol IEnumerable <MyTree>, elemento MyTreeElement) que sería un método de extensión para IEnumerable <MyTree> que devolvería IEnumerable <MyTreeElement> desde el cual debería comenzar a iterar. Entonces tal vez podría usar este método como foreach (elemento var en tree.StartFrom (someElement))).
Infierno

@inferno: Sí, podrías hacer eso fácilmente. Sin embargo, simplemente agregaría un método / propiedad a MyTreeElement que fuera más como:, IEnumerable<MyTreeElement> Childrenpor lo que podría hacer: foreach(var item in someElement.Children)- mucho más claro que usar métodos de extensión en mi opinión.
Reed Copsey

-1

Foreachiterará sobre su colección de la manera definida por su implementación de IEnumerable. Entonces, aunque puede omitir elementos (como se sugirió anteriormente), técnicamente aún está iterando sobre los elementos en el mismo orden.

No estoy seguro de lo que está tratando de lograr, pero su clase podría tener varias IEnumerablepropiedades, cada una de las cuales enumera los elementos en un orden específico.


-1

Si desea omitir la lectura de filas en a DataGridView, intente esto

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

Si desea copiar el contenido de uno DataGridViewa otro saltando filas, intente esto,

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

esto copia el contenido de uno DataGridViewa otro saltando 3 filas.


Esto no responde a la pregunta que se hizo: la pregunta no menciona DataGridViewen absoluto (o incluso un marco de interfaz de usuario).
NightOwl888

@ NightOwl888 esto fue respondido porque la pregunta era sobre omitir algunas iteraciones e iterar después de eso en foreach loop. En mi ejemplo, solo usé Skip () para aplicar en DataGridView.
Juned Khan Momin
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.