#概要
競技プログラミング中に必要なり、調べてみました。
2次元リストの行と列を入れ替える(転置する)には、リストのアンパックと組み込み関数のzip()をうまく使います。
zipは組み込み関数なので何かをimportする必要はありません。
実際のコードは以下のようになります。
#元のリスト
list_org = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
print(list_org)
#転置
list_transposed = [list(x) for x in zip(*list_org)]
print(list_transposed)
出典:
nkmk note様
#解説
list_transposed = [list(x) for x in zip(*list_org)]
の行が転置を行っています。
*list_orgのようにリストの前にアスタリスクをつけると「アンパック」という処理が行われます。
これは、リストの一番上の次元の要素を取り出して引数として渡す処理になります。
試しに以下のコードを実行してみます。
list_org = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
print(list_org)
結果は
[0, 1, 2] [3, 4, 5] [6, 7, 8]
となります。
printにlist_org[0]とlist_org[1]とlist_org[2]が渡されています。
(printに複数の引数を渡すとどうなるかは末尾の「補足」に軽く記載しました)
つまり今回の場合、
zip(*list_org)
は、
zip(list_org[0], list_org[1], list_org[2])
と同じ意味になります。
続いてzipですが、これは渡された引数それぞれのi番目の要素を取り出してタプルにする関数となっています。
公式リファレンスにわかりやすい例があったので転載します。
for item in zip([1, 2, 3], ['sugar', 'spice', 'everything nice']):
print(item)
(1, 'sugar')
(2, 'spice')
(3, 'everything nice')
この例ではzip()の一番目の引数に連番の数字のリスト、二番目の引数に文字列のリストを渡しています。
そしてzip()の結果、二つのリストで添え字が同じになる要素がタプルとしてまとめられています。
そしてそれぞれのタプルはiterableなクラス(for inが使えるクラス)としてひとまとめにされて返却されます。
(実際にtype()で型を見てみるとzipというクラスのようです)
今回の転置の
zip(list_org[0], list_org[1], list_org[2])
は、
list_org = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]なので、
zip([0, 1, 2], [3, 4, 5], [6, 7, 8])となり、
それぞれの引数のリストで同じ位置の要素がタプルでまとめられ、
(0, 3, 6)
(1, 4, 7)
(2, 5, 8)
となります。
もう実質転置された状態になっていますね。
しかし、2次元リストではなくタプルとそれをまとめたiterableなので最後にこれを変換します。
それを行うのが以下のコードの[list(x) for x in~]の部分です。
list_transposed = [list(x) for x in zip(*list_org)]
この構文でのリストの作成ですが実際の処理順はともかく、意味的には以下の画像のようになっています。
この構文によって、
タプルの(0, 3, 6)、(1, 4, 7)、(2, 5, 8)はlist(x)の部分で
それぞれリスト[0, 3, 6]、[1, 4, 7]、[2, 5, 8]になり、
さらにそれを[]で囲むことによって2次元リスト
[[0, 3, 6],[1, 4, 7],[2, 5, 8]]になります。
これで転置した2次元リストが出来上がりました。
#補足
補足ですがprintには複数の引数を渡すことが可能であり、例えば
print('a','b','c')
とすると出力は
a b c
と、引数全てがスペースでつながれて出力されます。