C# 如何使用LINQ在二维集合中转置尺寸?

C# 如何使用LINQ在二维集合中转置尺寸?,c#,linq,C#,Linq,考虑以下结构: IEnumerable<IEnumerable<int>> collection = new[] { new [] {1, 2, 3}, new [] {4, 5, 6}, new [] {7, 8, 9} }; IEnumerable集合=新[]{ 新[]{1,2,3}, 新[]{4,5,6}, 新[]{7,8,9} }; 如何枚举此集合以便获得由第一项、第二项等组成的IEnumerable集合 也就是说,{1,4,7

考虑以下结构:

IEnumerable<IEnumerable<int>> collection = new[] { 
    new [] {1, 2, 3}, 
    new [] {4, 5, 6}, 
    new [] {7, 8, 9} 
};
IEnumerable集合=新[]{
新[]{1,2,3},
新[]{4,5,6},
新[]{7,8,9}
};
如何枚举此集合以便获得由第一项、第二项等组成的
IEnumerable
集合

也就是说,{1,4,7},{2,5,8}

(虽然我选择的实现是
int[]
对象,但假设您只有
IEnumerable
功能。谢谢。)

(未经测试,但看起来不错)

公共静态类LinqExtensions
{
公共静态IEnumerable转置(此IEnumerable值)
{
如果(!values.Any())
返回值;
如果(!values.First().Any())
返回转置(value.Skip(1));
var x=values.First().First();
var xs=values.First().Skip(1);
var xss=values.Skip(1);
返回
新[]{new[]{x}
.Concat(xss.Select(ht=>ht.First())}
.Concat(新[]{xs}
.Concat(xss.Select(ht=>ht.Skip(1)))
.Transpose());
}
}
//输入:转置[[1,2,3],[4,5,6],[7,8,9]] //输出:[[1,4,7],[2,5,8],[3,6,9]] var result=new[]{new[]{1,2,3},new[]{4,5,6},new[]{7,8,9}.Transpose();
这里有一种使用生成器而不是递归的方法。阵列构造也更少,所以可能更快,但这完全是猜测

public static IEnumerable<IEnumerable<T>> Transpose<T>(
    this IEnumerable<IEnumerable<T>> @this) 
{
    var enumerators = @this.Select(t => t.GetEnumerator())
                           .Where(e => e.MoveNext());

    while (enumerators.Any()) {
        yield return enumerators.Select(e => e.Current);
        enumerators = enumerators.Where(e => e.MoveNext());
    }
}
公共静态IEnumerable转置(
this(可数@this)
{
var枚举数=@this.Select(t=>t.GetEnumerator())
。其中(e=>e.MoveNext());
while(枚举数.Any()){
产生返回枚举数。选择(e=>e.Current);
枚举数=枚举数。其中(e=>e.MoveNext());
}
}

如果保证所有元素的长度相同,则可以执行以下操作:

IEnumerable<IEnumerable<int>> Transpose(IEnumerable<IEnumerable<int>> collection)
{
    var width = collection.First().Count();
    var flattened = collection.SelectMany(c => c).ToArray();
    var height = flattened.Length / width;
    var result = new int[width][];

    for (int i = 0; i < width; i++)
    {
        result[i] = new int[height];
        for (int j = i, k = 0; j < flattened.Length; j += width, k++)
            result[i][k] = flattened[j];
    }

    return result;
}
IEnumerable转置(IEnumerable集合)
{
var width=collection.First().Count();
var=collection.SelectMany(c=>c.ToArray();
变量高度=展平。长度/宽度;
var结果=新整数[宽度][];
对于(int i=0;i
只要我的2美分 在纯linq中:

 var transpond =           collection.First().Select((frow,i)=>collection.Select(row=>row.ElementAt(i)));
或者带着一些不纯洁:

var r1 = collection.First().Select((frow, i) => collection.Select(row => row.ToArray()[i]));

假设所有序列的长度相同

static void Main(string[] args)
{
    IEnumerable<IEnumerable<int>> collection =
        new[]
        {
            new [] {1, 2, 3},
            new [] {4, 5, 6 },
            new [] {7, 8, 9}
        };
    Console.WriteLine("\tInitial");
    Print(collection);

    var transposed =
        Enumerable.Range(0, collection.First().Count())
                  .Select(i => collection.Select(j => j.ElementAt(i)));
    Console.WriteLine("\tTransposed");
    Print(transposed);
}

static void Print<T>(IEnumerable<IEnumerable<T>> collection)=>
    Console.WriteLine(string.Join(Environment.NewLine, collection.Select(i => string.Join(" ", i))));

+1我笑了,因为名为
recursive
的用户没有提供递归解决方案=d这假设所有序列的长度相同。但是,这很容易修复。你介意我编辑你的答案并添加更改吗?你有一个非常漂亮的解决方案。@Jason:所有的答案都假设在长度不等的情况下有一些行为。我确实考虑过这种行为,我认为终止这个序列是一个合理的反应。其他一些回答将在您提到的案例中出现。@recursive:Done。感谢您提供了非常漂亮的解决方案,并有机会对此做出一点贡献+1全天。仅供参考,您可以使用
.ElementAt
而不是
跳过
采取
单一
模式。回答得好。我想出了一个好主意。但我被
Select
重载搞糊涂了,它接受项和索引,但不使用项。所以我只使用了通过
可枚举获取的索引尝试了一下,当“ht”为空时,它在“ht=>ht.First()”部分抛出了一个异常。
var r1 = collection.First().Select((frow, i) => collection.Select(row => row.ToArray()[i]));
static void Main(string[] args)
{
    IEnumerable<IEnumerable<int>> collection =
        new[]
        {
            new [] {1, 2, 3},
            new [] {4, 5, 6 },
            new [] {7, 8, 9}
        };
    Console.WriteLine("\tInitial");
    Print(collection);

    var transposed =
        Enumerable.Range(0, collection.First().Count())
                  .Select(i => collection.Select(j => j.ElementAt(i)));
    Console.WriteLine("\tTransposed");
    Print(transposed);
}

static void Print<T>(IEnumerable<IEnumerable<T>> collection)=>
    Console.WriteLine(string.Join(Environment.NewLine, collection.Select(i => string.Join(" ", i))));
        Initial
1 2 3
4 5 6
7 8 9
        Transposed
1 4 7
2 5 8
3 6 9