/// <summary> /// Transpose <paramref name="source"/>. /// </summary> /// <typeparam name="T">Type of element of the nested <see cref="IEnumerable{T}"/>.</typeparam> /// <param name="source">Sequence which will be transposed.</param> /// <param name="mode">How non-uniform sequences are handled.</param> /// <returns>Transposed <paramref name="source"/>.</returns> public static List <T[]> Transpose <T>(this IList <IList <T> > source, TransposeMode mode = TransposeMode.ErrorOnMissing) { if (source is null) { throw new ArgumentNullException(nameof(source)); } if (source.Count == 0) { return(new List <T[]>()); } List <T[]> lines = new List <T[]>(); for (int j = 0; ; j++) { T[] line = new T[source.Count]; bool flag = false; for (int i = 0; i < source.Count; i++) { bool value = j < source[i].Count; flag |= value; if (value) { line[i] = source[i][j]; } else { switch (mode) { case TransposeMode.StripOnMissing: return(lines); case TransposeMode.DefaultOnMissing: line[i] = default; break; } } } if (flag) { if (mode == TransposeMode.ErrorOnMissing) { throw new ArgumentOutOfRangeException("All nested enumerators must have same count.", nameof(source)); } lines.Add(line); } else { break; } } return(lines); }
/// <summary> /// Transpose <paramref name="source"/>. /// </summary> /// <typeparam name="T">Type of element of the nested <see cref="IEnumerable{T}"/>.</typeparam> /// <param name="source">Sequence which will be transposed.</param> /// <param name="mode">How non-uniform sequences are handled.</param> /// <returns>Transposed <paramref name="source"/>.</returns> public static IEnumerable <IEnumerable <T> > Transpose <T>(this IEnumerable <IEnumerable <T> > source, TransposeMode mode = TransposeMode.ErrorOnMissing) { // https://stackoverflow.com/a/10555037/7655838 from https://stackoverflow.com/questions/10554866/how-do-you-transpose-dimensions-in-a-2d-collection-using-linq if (source is null) { throw new ArgumentNullException(nameof(source)); } return(Work()); IEnumerable <IEnumerable <T> > Work() { if (!source.Any()) { yield break; } IEnumerator <T>[] enumerators = source.Select(t => t.GetEnumerator()).ToArray(); try { T[] line = new T[enumerators.Length]; while (true) { bool atLeastOneTrue = false; bool allTrue = true; for (int i = 0; i < enumerators.Length; i++) { bool value = enumerators[i].MoveNext(); atLeastOneTrue |= value; allTrue &= value; if (value) { line[i] = enumerators[i].Current; } else { switch (mode) { case TransposeMode.StripOnMissing: yield break; case TransposeMode.DefaultOnMissing: line[i] = default; break; } } } if (atLeastOneTrue) { if (mode == TransposeMode.ErrorOnMissing && !allTrue) { throw new ArgumentOutOfRangeException("All nested enumerators must have same count.", nameof(source)); } else { yield return(line); } } else { break; } } } finally { for (int i = 0; i < enumerators.Length; i++) { enumerators[i].Dispose(); } } } }