如果我有一个包含任意数量列表的列表,如下所示:
var myList = new List<List<string>>() { new List<string>() { "a", "b", "c", "d" }, new List<string>() { "1", "2", "3", "4" }, new List<string>() { "w", "x", "y", "z" }, // ...etc... };
…有什么办法可以将列表“压缩”或“旋转”成类似的形式?
{ { "a", "1", "w", ... }, { "b", "2", "x", ... }, { "c", "3", "y", ... }, { "d", "4", "z", ... } }
显而易见的解决方案是执行以下操作:
public static IEnumerable<IEnumerable<T>> Rotate<T>(this IEnumerable<IEnumerable<T>> list) { for (int i = 0; i < list.Min(x => x.Count()); i++) { yield return list.Select(x => x.ElementAt(i)); } } // snip var newList = myList.Rotate();
…但是我想知道是否有使用linq或其他方法的更清洁方法?
您可以滚动自己的ZipMany实例,该实例手动迭代每个枚举。与GroupBy投影每个序列后使用的序列相比,这可能会在较大的序列上表现更好:
GroupBy
public static IEnumerable<TResult> ZipMany<TSource, TResult>( IEnumerable<IEnumerable<TSource>> source, Func<IEnumerable<TSource>, TResult> selector) { // ToList is necessary to avoid deferred execution var enumerators = source.Select(seq => seq.GetEnumerator()).ToList(); try { while (true) { foreach (var e in enumerators) { bool b = e.MoveNext(); if (!b) yield break; } // Again, ToList (or ToArray) is necessary to avoid deferred execution yield return selector(enumerators.Select(e => e.Current).ToList()); } } finally { foreach (var e in enumerators) e.Dispose(); } }