LoginSignup
3
3

More than 5 years have passed since last update.

LINQで入れ子になっているListの並びの縦横を入れ替える

Posted at

概要

テーブルのような2次元のListがあるとします。

new List<List<string>>()
{
    new List<string>() {"1a", "1b", "1c"},
    new List<string>() {"2a", "2b", "2c"},
    new List<string>() {"3a", "3b", "3c"}
}

下記のように横のListが縦に並び変わるようなメソッドを作成していきます。

// 変換後
new List<List<string>>()
{
    new List<string>() {"1a", "2a", "3a"},
    new List<string>() {"1b", "2b", "3b"},
    new List<string>() {"1c", "2c", "3c"}
}

図にすると下記の形です。

変換前

インデックス 0 1 2
0 1a 1b 1c
1 2a 2b 2c
2 3a 3b 3c

変換後

インデックス 0 1 2
0 1a 2a 3a
1 1b 2b 3b
2 1c 2b 3c

実装

正方形に対して

まずList自体の数と、それぞれのList<string>の中身の数が同じときの実装です。
実コードとしては以下になります。

static void Main(string[] args)
{
    var targetList = new List<List<string>>()
    {
        new List<string>() {"1a", "1b", "1c"},
        new List<string>() {"2a", "2b", "2c"},
        new List<string>() {"3a", "3b", "3c"}
    };
    var resultList = TransposeColumnsAndRows(targetList);
}

private static List<List<string>> TransposeColumnsAndRows(List<List<string>> targetList)
{
    var resultList = new List<List<string>>();    

    foreach (var row in targetList.Select((v, i) => new { v, i }))
    {
        while (resultList.Count() < row.v.Count())
            resultList.Add(new List<string>());

        foreach (var col in row.v.Select((v, i) => new { v, i }))
        {
            resultList[col.i].Add(col.v);
        }
    }

    return resultList;
}

TransposeColumnsAndRowsメソッドで縦横を入れ替えます。
中では何をしているかというと、新たにListを作成して、横の数だけ縦のListを生成し、横のListを順々に詰めているだけです。

結果

resultList の中身は以下のような形になります。

new List<List<string>>()
{
    new List<string>() {"1a", "2a", "3a"},
    new List<string>() {"1b", "2b", "3b"},
    new List<string>() {"1c", "2c", "3c"}
}

正方形でないパターン

ただ、このままだと横のListが空だった場合や、縦と横が同じ数のList以外ではズレが生じます。
下記のようなListだと2dがあふれてしまいますね。

// 変換前
new List<List<string>>()
{
    new List<string>() {"1a", "1b", "1c"},
    new List<string>() {"2a", "2b", "2c", "2d"},
    new List<string>() {"3a", "3b", "3c"}
}
// 変換後
new List<List<string>>()
{
    new List<string>() {"1a", "2a", "3a"},
    new List<string>() {"1b", "2b", "3b"},
    new List<string>() {"1c", "2c", "3c"},
    new List<string>() {"2d"}
}

ここの対応に関しては、どう対応するか色々方法はあるとおもいます。
今回は縦に足りない分を指定した文字で埋める形にしてみました。
以下、実装コードです。

static void Main(string[] args)
{
    var targetList = new List<List<string>>()
    {
        new List<string>() {"1a", "1b", "1c"},
        new List<string>() {"2a", "2b", "2c", "2d"},
        new List<string>() {"3a", "3b", "3c"}
    };
    var resultList = TransposeColumnsAndRows(targetList, string.Empty);
}

private static List<List<string>> TransposeColumnsAndRows(List<List<string>> targetList, string pad)
{
    var resultList = new List<List<string>>();

    foreach (var row in targetList.Select((v, i) => new { v, i }))
    {
        while (resultList.Count() < row.v.Count())
            resultList.Add(new List<string>());

        foreach (var col in row.v.Select((v, i) => new { v, i }))
        {
            while (row.i > resultList[col.i].Count())
                resultList[col.i].Add(string.Empty);

            resultList[col.i].Add(col.v);
        }
    }

    foreach (var row in resultList)
    {
        while (row.Count() < targetList.Count())
        {
            row.Add(pad);
        }
    }

    return resultList;
}

結果

new List<List<string>>()
{
    new List<string>() {"1a", "2a", "3a"},
    new List<string>() {"1b", "2b", "3b"},
    new List<string>() {"1c", "2c", "3c"},
    new List<string>() {"", "2d", ""}
}

これで、足りない部分がから文字で埋められました。
テーブルのような正方形の形を保ちつつ、縦横を入れ替えることができました。

3
3
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3