Как вы переносите размеры в 2D-коллекции с помощью LINQ?

Рассмотрите следующую структуру:

<code>IEnumerable<IEnumerable<int>> collection = new[] { 
    new [] {1, 2, 3}, 
    new [] {4, 5, 6}, 
    new [] {7, 8, 9} 
};
</code>

Как я могу перечислить эту коллекцию, чтобы получитьIEnumerable<int> коллекции, состоящие из первых предметов, вторых предметов и т. д .

То есть {1, 4, 7}, {2, 5, 8}, ...

(Хотя реализация, которую я выбрал, этоint[] объекты, предположим, у вас есть толькоIEnumerable<int> функциональность. Благодарность.

Ответы на вопрос(4)

Код кредита идет сюда (не проверено, но выглядит хорошо).

{
    public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> values)
    {
        if (!values.Any()) 
            return values;
        if (!values.First().Any()) 
            return Transpose(values.Skip(1));

        var x = values.First().First();
        var xs = values.First().Skip(1);
        var xss = values.Skip(1);
        return
         new[] {new[] {x}
           .Concat(xss.Select(ht => ht.First()))}
           .Concat(new[] { xs }
           .Concat(xss.Select(ht => ht.Skip(1)))
           .Transpose());
    }
}
//Input: transpose [[1,2,3],[4,5,6],[7,8,9]]
//Output: [[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();     
 jeebs11 мая 2012 г., 18:33
+ 1 выглядит сумасшедшим;) Попробовал его, и он вызвал исключение в части "ht => ht.First ()", когда ht был пуст.

 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]));
 recursive11 мая 2012 г., 18:30
FYI, вы можете использовать.ElementAt вместоSkip, Take, Single шаблон
Решение Вопроса

который использует генератор вместо рекурсии. Там также меньше построение массивов, так что это может быть быстрее, но это полностью предположение.

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());
    }
}
 recursive11 мая 2012 г., 18:32
@ Jason: Все ответы предполагают некоторое поведение в случае неравной длины. Я считал это поведение и думал, что завершение последовательности было разумным ответом. Некоторые другие ответы будут добавлены в случае, если вы упомянули.
 jason11 мая 2012 г., 18:29
Это предполагает, что все последовательности имеют одинаковую длину.
 phoog11 мая 2012 г., 18:18
clever, лаконично: + 1
 Tejs11 мая 2012 г., 18:16
+ 1 Я посмеялся над тем, что пользователь назвалrecursive не предлагал рекурсивное решение = D
 jason11 мая 2012 г., 18:31
Однако это легко исправить. Вы не против, если я отредактирую ваш ответ и добавлю изменение? У вас есть невероятно красивое решение.

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;
}

Ваш ответ на вопрос