2010-12-02 16 views
33

de Trabajo de foreach: que sé,Counter en bucle foreach en C#

foreach es un bucle que itera a través de una colección o matriz de una por uno, a partir de 0 índice hasta el último artículo de la colección.

Por lo tanto, si tengo n elementos en una matriz.

foreach (var item in arr) 
{ 

} 

entonces, en, primera iteración, item = arr [0];
luego, en 2nd, item = arr [1];
.
.
.
en último (nth), item = arr [n-1];

Conclusión: de trabajo parece que en cada iteración se sabe que el valor que debe ser tomado de matriz o se conoce el índice del elemento que se lanzará desde la matriz.

Ahora mi pregunta es: ¿Cómo puedo obtener el índice de un artículo sin usar una nueva variable?

foreach (string item in mylist) 
{ 
    if (item == "myitem") 
    { 
     // get index of item 
     break; 
    } 
} 
+0

La pregunta es canónica * [¿Cómo se obtiene el índice de la iteración actual de un bucle foreach?] (Http://stackoverflow.com/questions/43021) *. –

+1

Posible duplicado de * [¿Cómo se obtiene el índice de la iteración actual de un ciclo foreach?] (Http://stackoverflow.com/questions/43021/how-do-you-get-the-index-of-the -current-iteration-of-a-foreach-loop) *. –

Respuesta

69

Depende de lo que quiere decir con "it". El iterador sabe a qué índice se llega, sí, en el caso de List<T> o una matriz. Pero no hay un índice general dentro de IEnumerator<T>. Si se trata de iterar sobre una colección indexada o no depende de la implementación. Muchas colecciones no son compatibles con la indexación directa.

(De hecho, foreach no siempre utilizar un iterador en absoluto. Si el tipo en tiempo de compilación de la colección es una matriz, el compilador iterar sobre ella usando array[0], array[1] etc. Asimismo la colección puede tener una método llamado GetEnumerator() que devuelve un tipo con los miembros apropiados, pero sin ninguna aplicación de IEnumerable/IEnumerator a la vista)

opciones para mantener un índice:.

  • utilizar un bucle for
  • Utilice una variable separada
  • Utilice una proyección que proyecte cada elemento a un par de índice/valor, p.

    foreach (var x in list.Select((value, index) => new { value, index })) 
    { 
        // Use x.value and x.index in here 
    } 
    
  • utiliza mi clase SmartEnumerable que es un poco como la opción anterior

Todos menos la primera de estas opciones funcionará si la colección está indexado de forma natural.

+0

@Downvoter: ¿me gustaría comentar? –

+0

Jon ....... Soy un gran admirador de tus respuestas. – AlwaysAProgrammer

+1

Su enfoque de proyección es elegante y simple, ¡voy a pellizcar eso! – madman1969

17

Uso for en lugar de foreach. foreach no expone su funcionamiento interno, enumera todo lo que es IEnumerable (que no tiene que tener un índice en absoluto).

for (int i=0; i<arr.Length; i++) 
{ 
    ... 
} 

Además, si lo que estamos tratando de hacer es encontrar el índice de un elemento particular de la lista, que no tiene que repetir en absoluto por sí mismo. Use Array.IndexOf(item) en su lugar.

+0

Creo que debería ser i JasonS

+0

Whoops. Eso es correcto, por supuesto. Gracias. –

+0

Como se dijo algunas veces en otras respuestas, tiene que ser un IEnumerable para trabajar en un foreach. –

1

Esto solo es válido si está iterando a través de una matriz; ¿Qué pasaría si estuvieras iterando a través de un tipo diferente de colección que no tiene la noción de acceder por índice? En el caso de matriz, la forma más fácil de conservar el índice es simplemente usar un ciclo de vainilla.

10

Su comprensión de foreach está incompleta.

Funciona con cualquier tipo que expone IEnumerable (o implementa un método GetEnumerable) y utiliza el IEnumerator devuelto para iterar sobre los elementos de la colección.

La forma en que Enumerator hace esto (usando un índice, yield declaración o magia) es un detalle de implementación.

Con el fin de lograr lo que desea, debe utilizar un bucle for:

for (int i = 0; i < mylist.Count; i++) 
{ 
} 

Nota:

Conseguir el número de elementos de una lista es ligeramente diferente dependiendo del tipo de de la lista

For Collections: Use Count [property] 
For Arrays:  Use Length [property] 
For IEnumerable: Use Count() [Linq method] 
+0

Creo que es mágico. – Brad

+0

'foreach' realmente funciona con cualquier tipo que tenga un método' GetEnumerator' (si ese método luego devuelve un objeto con una propiedad 'Current' apropiada y el método' MoveNext'). Los tipos en realidad no necesitan implementar 'IEnumerable' /' IEnumerator'. – LukeH

+0

@LukeH - punto justo. Respuesta actualizada – Oded

0

No todas las colecciones tienen índices. Por ejemplo, puedo usar un Dictionary con foreach (y recorrer todas las claves y valores), pero no puedo escribir llegar a elementos individuales utilizando dictionary[0], etc. dictionary[1]

Si yo quería recorrer un diccionario y hacer un seguimiento de un índice, tendría que usar una variable separada que yo mismo incrementara.

2

Probablemente sentido, pero ...

foreach (var item in yourList.Select((Value, Index) => new { Value, Index })) 
{ 
    Console.WriteLine("Value=" + item.Value + ", Index=" + item.Index); 
} 
0

La secuencia que se reiteró en un bucle foreach no admita la indexación o conocer un concepto tan sólo tiene que poner en práctica un método llamado GetEnumerator que devuelve un objeto que como un mínimo tiene la interfaz de IEnumerator, aunque implica que no es necesario. Si sabe que lo que itera admite indización y necesita el índice, le sugiero que utilice un bucle for.

Una clase de ejemplo que se puede utilizar en foreach:

class Foo { 

     public iterator GetEnumerator() { 
      return new iterator(); 
     } 

     public class iterator { 
      public Bar Current { 
       get{magic} 
      } 

      public bool MoveNext() { 
       incantation 
      } 
     } 
    } 
+0

'GetEnumerator()' ni siquiera necesita devolver un tipo que implemente 'IEnumerator' ... –

+0

@Jon Skeet: ¿Qué quiere decir? ¿No es 'IEnumerator GetEnumerator();' la firma del único método definido en 'IEnumerable'? –

+0

@Yodan: Sí, pero tampoco tiene que implementar IEnumerable :) –

0

De MSDN:

La declaración foreach repite un grupo de instrucciones incrustadas para cada elemento en una matriz o un objeto colección que implementa el sistema .Collections.IEnumerable o System.Collections.Generic.IEnumerable (Of T) interfaz.

Por lo tanto, no es necesariamente Array. Incluso podría ser una colección perezosa sin ninguna idea sobre el recuento de elementos en la colección.

5

O incluso más simple si no desea utilizar mucho linq y por alguna razón no desea utilizar un bucle for.

int i = 0; 
foreach(var x in arr) 
{ 
    //Do some stuff 
    i++; 
} 
+0

Sí, la vida es simple. –

+0

tienes 'arr.Length' como colección, ¿se supone que es 'foreach (var x in arr)'? – karthick

+0

@karthick - Wow, fue hace casi 4 años que escribí eso, pero por supuesto eres correcto. Es curioso que nadie más haya visto eso antes que tú . :) Permítanme editar si todavía puedo. – BlueVoodoo