16

次の構造を検討してください。

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

IEnumerable<int>このコレクションを列挙して、最初のアイテム、2番目のアイテムなどで構成されるコレクションを取得するにはどうすればよいですか?

つまり、{1、4、7}、{2、5、8}、..。

(私が選択した実装はint[]オブジェクトですが、機能しかないことを前提としていIEnumerable<int>ます。ありがとうございます。)

4

5 に答える 5

21

これは、再帰の代わりにジェネレーターを使用するアプローチです。アレイの構築も少ないので、高速になる可能性がありますが、それは完全に推測です。

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());
    }
}
于 2012-05-11T16:15:17.530 に答える
3

コードクレジットはここにあります(テストされていませんが、問題ないように見えます)。

public static class LinqExtensions
{
    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());
    }
}
//入力:転置[[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();     
于 2012-05-11T16:05:40.067 に答える
3

純粋なlinqでちょうど私の2セント:

 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]));
于 2012-05-11T16:27:01.147 に答える
1

すべてのシーケンスが同じ長さであると仮定します。

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
于 2019-08-05T09:30:17.457 に答える
0

すべての要素が同じ長さであることが保証されている場合は、次のようにすることができます。

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;
}
于 2012-05-11T16:16:54.947 に答える