[Power Query] １列に積み重なったデータを表形式にするベストプラクティスは？ (4) Table.AlternateRows → Table.FromColumns

※この記事は 2023/7/22 に作成しました。
※オプションで、「地域の設定」の「クエリステップ」は、「常に英語」に設定されています。日本語で使用している場合は、各自環境で作成されるコードに読み替えてください。

以下のように、複数の項目が1列になっているデータをテーブルにする方法の4番目です。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/e87b3164-4a5b-f0dc-49fe-af959488dddc.png"/>

# Index
- [(1) Table.AddIndexColumn → Table.Pivot](https://qiita.com/spumoni/items/f949f370aea5a831aeea)
- [(2) Table.Split → Table.Transpose → Table.Combine](https://qiita.com/spumoni/items/0de5b66f3d71b69572bd)
- [(3) List.Split → Table.FromRows](https://qiita.com/spumoni/items/0bcf50c7720f93804fcb)
- [(4) Table.AlternateRows → Table.FromColumns](https://qiita.com/spumoni/items/679150a28de7a9a30f1d)
- [(5) List.Alternate → Table.FromColumns](https://qiita.com/spumoni/items/4aac2d40984ba4c244ce)
- [(6) まとめ](https://qiita.com/spumoni/items/3503970baa038e349a79)


# 解法4: Table.AlternateRowsを使う
## Table.AlternateRows
　まず最初に、Table.AlternateRows関数の動作について説明します。
　「ホーム」タブで「行の削減」グループの「行の削除」→「代替業の削除」を選択します。
　表示されたダイアログの「削除する最初の行」に２、「削除する行の数」に２、「保持する行の数」に１を入力して実行します。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/4ac15b48-d9ff-8568-4c4a-28ca93d34cf6.png"/>

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/db61c421-1cce-73f0-87bc-cba955b6cf50.png"/>

 この操作で生成されるコードは、以下のようになります。

```
RemovedAlternateRows = 
    Table.AlternateRows(
        Source,
        1,
        2,
        1
)
```

　構文は以下のようになっています。

```text:構文
Table.AlternateRows(
    table as table, 
    offset as number, 
    skip as number, 
    take as number
) as table
```

　第二引数のoffsetが「削除する最初の行」になりますが、入力した値は **2** ですが、コードでは **1** になっています。これは、コードの上では **0** からスタートしているためです。

　この関数を使って、それぞれの列の値を作成していきます。

　2列目の著者名を抜き出すためには、「削除する最初の行」に3を入れればいいのではと思うかもしれませんが、そうすると一番最初の書籍名が残ってしまいます。
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/b71943c0-beeb-bce5-6b32-ad07161058f1.png"/>
　なので、最初にテーブルの最初のレコードをスキップして処理を行うようにします。

```
RemovedAlternateRows = 
    Table.AlternateRows(
        Table.Skip(Source, 1),
        1,
        2,
        1
    )
```

<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/2c7ffb70-7a75-29b7-5f77-66c77bc4bc1e.png"/>

　同様に、出版日も最初の2つのレコードをスキップして処理を行い、3つの項目の作成方法が出来上がります。

https://learn.microsoft.com/ja-jp/powerquery-m/table-alternaterows

## Table.FromColumns
　これを1つのテーブルにまとめるのには、**Table.FromColumns** 関数を使います。前回使用した Table.FromRowsが横に展開したのに対して、Table.FromColumnsは縦に展開します。ここからは、詳細エディタを使用してコードを書き込んでいきます。

```text:構文
Table.FromColumns(
    lists as list, 
    optional columns as any
) as table
```

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/1acfd86a-5325-dad2-cab9-4f93bc4b107a.png"/>

　第一引数は、入れ子になったリストにしなければなりません。3項目をつなぎ合わせると、以下のようなコードになります。

```
Column1 = Table.ToList( Table.AlternateRows( Source, 1,2,1 ) ),
Column2 = Table.ToList( Table.AlternateRows( Table.Skip( Source, 1 ), 1,2,1 ) ),    
Column3 = Table.ToList( Table.AlternateRows( Table.Skip( Source, 2 ), 1,2,1 ) ),    
TableAlternateRows = 
    Table.FromColumns( 
        {
            Column1, 
            Column2, 
            Column3 
        }
    )
```
　関数を入れ子にすると、以下のようになります。

```
TableAlternateRows = Table.FromColumns(
    {
        Table.ToList(
            Table.AlternateRows(Source, 1,2,1)
        ),
        Table.ToList(
            Table.AlternateRows(
                Table.Skip(Source,1), 
                1,2,1
            )
        ),
        Table.ToList(
            Table.AlternateRows(
                Table.Skip(Source,2), 1,2,1
            )
        )
    }
)
```

　列ごとに並べて記述するのが見苦しいと思うなら、List.Transformで繰り返し処理を行うこともできます。Table.Skipの第二引数の `_` は、0～2までの値が入ります。

```
TableAlternateRows = Table.FromColumns(
    List.Transform(
        {0..2},
        each Table.ToList( 
            Table.AlternateRows( 
                Table.Skip( Source, _), 
                1, 2, 1
            ) 
        )
    )
)
```

　Table.ToListを使わずに、以下のように書くこともできます。

```
TableAlternateRows = Table.FromColumns(
    List.Transform(
        {0..2},
        each Table.AlternateRows( 
                Table.Skip( Source, _), 
                1, 2, 1
        )[Column1]
    )
)
```

 テーブルをTable.ToColumns関数でテーブルを入れ子になったリストに変換し、List.Firstでリスト内の最初の項目のみを抜き出してリストにするという方法もあります。

```
TableAlternateRows = Table.FromColumns(
    List.Transform(
        {0..2},
        each List.First(
            Table.ToColumns(
                Table.AlternateRows( 
                    Table.Skip( Source, _), 
                    1, 2, 1
                )
            )
        )
    )
)
```


https://qiita.com/PowerBIxyz/items/3bf610ee4e8a7926f6ed

## ソースコード

```text
let
    // ファイルの読み込み
    Source = Table.FromColumns(
        {
            Lines.FromBinary(
                File.Contents( "** File Name **" ),
                null,
                null,
                932  // シフトJIS
            )
        }
    ),
    // 変換処理
    TableAlternateRows = Table.FromColumns(
        List.Transform(
            {0..2},
            each Table.AlternateRows( 
                    Table.Skip( Source, _), 
                    1, 2, 1
            )[Column1]
        )
    ),
    // 項目名の変更
    RenamedColumns =  Table.RenameColumns(
        TableAlternateRows,
        {
            {"Column1", "書名"}, 
            {"Column2", "著者名"}, 
            {"Column3", "出版日"}
        }
    )
in
    RenamedColumns
```