"转动"IEnumerable <IEnumerable <T >> 90度

Run*_* FS 8 c# linq algorithm declarative

我正在寻找的是一个基本的操作(我肯定有一个名字,我只是没有意识到atm).我有一个矩阵像:

{1,2,3}

{A,N,F}

{7,8,9}

我想改变它

{1,A,7}

{2,N,8}

{3,F,9}

(以上只是对象的标识符而不是实际值.实际对象属于同一类型且无序)

我更喜欢它的声明性解决方案,但速度是一个因素.我将不得不转动相当多的表(每分钟100k个单元),而慢速版将在关键路径上.

但是我对可读解决方案仍然更感兴趣.我正在寻找下面的替代解决方案.(换句话说,我不是指变化,而是一种不同的方法)

var  arrays = rows.Select(row => row.ToArray());
var cellCount = arrays.First().Length;
for(var i = 0;i<cellCount;i++){
  yield return GetRow(i,arrays);
}

IEnumerable<T> GetRow(int i,IEnumerable<T[]> rows){
  foreach(var row in rows}{
     yield return row[i]; 
  }
}
Run Code Online (Sandbox Code Playgroud)

在两个几乎同样可读的解决方案中,我会更快,但可读性在速度之前

编辑 它将始终是一个方阵

Jef*_*ado 10

我对这个实现有点不确定.它具有迭代器本地的副作用,但对我来说看起来很干净.这假定每个序列长度相同但应该适用于任何序列.您可以将其视为可变长度Zip()方法.它应该比其他答案中找到的其他链接LINQ解决方案表现更好,因为它只使用工作所需的最少操作.如果不使用LINQ,可能会更好.甚至可能被认为是最佳的.

public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> source)
{
    if (source == null) throw new ArgumentNullException("source");
    var enumerators = source.Select(x => x.GetEnumerator()).ToArray();
    try
    {
        while (enumerators.All(x => x.MoveNext()))
        {
            yield return enumerators.Select(x => x.Current).ToArray();
        }
    }
    finally
    {
        foreach (var enumerator in enumerators)
            enumerator.Dispose();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 附带说明一下,可能会删除对“ToArray()”的第二次调用。所以如果你有很多序列要压缩,那就更好了。 (2认同)