.NET Iterate a través de un IEnumerable varios elementos a la vez

Dada una colección, necesito iterar a través de todos los elementos tres (o alguna otra cantidad) a la vez. Por ejemplo:

string[] exampleData = {"John", "Doe", "1.1.1990", "Jane", "Roe", "2.2.1980"} for(int i = 0; i < exampleData.Length; i += 3) { CreateUser(foreName: exampleData[i], surName: exampleData[i+1], dateOfBirth: exampleData[i+2]); } 

¿Cómo podría reproducir esto de manera eficiente si exampleData fuera un IEnumerable en lugar de una matriz?

Un enfoque eficiente sería con un método de extensión:

 public static IEnumerable> ChunksOf(this IEnumerable sequence, int size) { List chunk = new List(size); foreach (T element in sequence) { chunk.Add(element); if (chunk.Count == size) { yield return chunk; chunk = new List(size); } } } 

Podrías usarlo así:

 foreach (IList chunk in exampleData.ChunksOf(3)) { CreateUser(foreName: chunk[0], surName: chunk[1], dateOfBirth: chunk[2]); } 

Tenga en cuenta que si sequence.Count() no es un múltiplo entero de size , entonces ChunksOf descarta la última parte parcial. Si, por el contrario, desea devolver un fragmento parcial, puede agregarlo al final: if (chunk.Count > 0) yield return chunk; .

Este fragmento agrupa su matriz en conjuntos de 3 elementos y luego crea un usuario para cada conjunto.

  exampleData.Select((elem, index) => new {elem, index}) .GroupBy(x => x.index/3) .Select(x => CreateUser( x.ElementAt(0).elem, x.ElementAt(1).elem, x.ElementAt(2).elem)); 

Naturalmente, deberá asegurarse de que la longitud de la matriz sea un múltiplo de 3.

Aunque prefiero el enfoque de Michael, es posible que prefiera algo un poco más específico si necesita un análisis de campo específico (por ejemplo, análisis de DOB)

 public static IEnumerable ExtractUsers(IEnumerable input) { int i = 0; string forename; string surname; string dateofbirth; foreach (string current in input) { switch (i) { case 0: one = forename; break; case 1: two = surname; break; case 2: three = dateofbirth; i = -1; //uck, this will get incremented at the bottom yield return CreateUser(forename, surname, dateofbirth); break; } i++; } } 

Take() y Skip() harán lo que quieras, pero te aconsejaría que evites utilizar matrices como esta. Sería mejor crear una clase Person con las propiedades FirstName , DateOfBirth y DateOfBirth y mantener una matriz de esas.

¿Qué tal si olvidamos foreach, las cosas elegantes de linq, las sublistas temporales, etc., y volvemos a las raíces? 🙂

Llame a .GetEnumerator () y llame a .MoveNext () tres veces en una iteración. Eso es lo que la enumeración es en su núcleo.

Las respuestas anteriores me parecen demasiado complicadas. Esto es simple y duro :-).

Puedes usar LINQ

  string[] exampleData = {"John", "Doe", "1.1.1990", "Jane", "Roe", "2.2.1980"}; int chunkSize = 3; var seqences = from seqIndex in Enumerable.Range(0, exampleData.Length) group exampleData[seqIndex] by seqIndex / chunkSize; foreach (var sub in seqences) { CreateUser(sub.ToList()[0], sub.ToList()[1], sub.ToList()[2]); } 

Editar:

  var seqences = from m in Enumerable.Range(0, exampleData.Count()) group exampleData.ToList()[m] by m / chunkSize; 

o

  int chunkSize = 3; var seqences = Enumerable.Range(0, exampleData.Count()) .GroupBy(m => m/chunkSize, m => exampleData.ToList()[m]);