¿Hay alguna forma de transformar un IEnumerable<int[]> en IEnumerable<int>[] ? Concretamente tengo un siguiente IEnumerable:
IEnumerable<int[]> data = new List<int[]>() { new int[]{1,11}, new int[]{2,22}, new int[]{3,33}, new int[]{4,44}, // ... // ... };y quiero convertirlo en la siguiente forma:
IEnumerable<int>[] data = new List<int>[] { new List<int>(){1,2,3,4 }, new List<int>(){11,22,33,44} };La única solución que he encontrado hasta ahora es la siguiente:
public static IEnumerable<int>[] Convert(IEnumerable<int[]> data) { var length = data.First().Length; var output = new List<int>[length]; for (int i = 0; i < length; i++) output[i] = new List<int>(); foreach (var entry in data) { for (int i = 0; i < length; i++) { output[i].Add(entry[i]); } } return output; } Sin embargo, esto no es ideal, ya que necesito iterar sobre todo el conjunto de datos. La solución deseada sería hacer uso de LINQ o características de patrón de iterador incorporado ( yield return ). ¿Hay alguna solución mejor para este problema?
Si no le importan las múltiples enumeraciones de data , puede hacer esto:
public static IEnumerable<int>[] Convert(IEnumerable<int[]> data) { var length = data.First().Length; var output = new IEnumerable<int>[length]; for (int i = 0; i < length; i++) { output[i] = CustomEnumerable(i); } return output; IEnumerable<int> CustomEnumerable(int index) { foreach (var entry in data) { yield return entry[index]; } } } Como puede ver, en lugar de completar listas, estoy devolviendo IEnumerable<int> s personalizados, que se crean con una función de iterador local (usando yield return ).
Si le importa iterar data solo una vez, podría hacer algo como esto:
IEnumerable<int>[] Convert(IEnumerable<int[]> data) { var found = new List<int[]>(); using var enumerator = data.GetEnumerator(); var proxy = ProxyEnumerable(); var length = proxy.First().Length; var output = new IEnumerable<int>[length]; for (int i = 0; i < length; i++) { output[i] = CustomEnumerable(i); } return output; IEnumerable<int> CustomEnumerable(int index) { foreach (var entry in proxy) { yield return entry[index]; } } IEnumerable<int[]> ProxyEnumerable() { foreach (var value in found) { yield return value; } while (enumerator.MoveNext()) { var value = enumerator.Current; found.Add(value); yield return value; } } } Aquí agregué otro IEnumerable<int[]> que está llenando una List<int[]> a medida que iteramos sobre él. Para que data se iteren solo una vez, y la iteración posterior use el caché.
Tengo una breve sugerencia con LINQ. Con el siguiente ejemplo, puede obtener una matriz irregular
var maxLength = data.Max(x => x.Length); var converted = new IEnumerable<int>[maxLength] .Select((dst, index) => data .Select(src => src.Length > index ? src[index] : default) .Where(n => n != default));y con esto puedes cortar tu matriz fuente en matriz
var minLength = data.Min(x => x.Length); var converted = new IEnumerable<int>[minLength] .Select((dst, index) => data .Select(src => src[index]));