Pythonのリストを結合するzip関数の逆の挙動を実現する方法について、今日初めて知ったので記事として残しておきます。
そもそもzip関数とは
zip関数は次の例のように、複数のイテラブル(下の例の場合はリスト)のi番目の要素をまとめた新しいイテレータを作る関数です。
name = ("Sato", "Tanaka", "Yamada") score = (70, 80, 90) # リストを作ったり print(list(zip(name, score))) # [('Sato', 70), ('Tanaka', 80), ('Yamada', 90)] # ループを回したり for n, s in zip(name, score): print(n, s) # Sato 70 # Tanaka 80 # Yamada 90
これと逆のこと、つまり
pair = [('Sato', 70), ('Tanaka', 80), ('Yamada', 90)]
というリストが与えられたときに、
name, score = unzip(pair)
といって名前とスコアのリストをそれぞれ得る、というような操作がしたいことがあるのですが、Pythonにunzipという関数は定義されていないようです。
unzipの実現方法
結論から言うと、次のコードでunzipが実現できます。
pair = [('Sato', 70), ('Tanaka', 80), ('Yamada', 90)] name, score = zip(*pair) print(name) # ('Sato', 'Tanaka', 'Yamada') print(score) # (70, 80, 90)
なぜそうなるのか?
注目すべきは zip(*pair)の部分です。zipの引数の前にアスタリスクがついています。
関数呼び出しの引数の前についているアスタリスクは、公式ドキュメントにもあるように展開されて解釈されます。
つまり、先ほどの例だと
pair = [('Sato', 70), ('Tanaka', 80), ('Yamada', 90)] zip(*pair)
この2行目の引数の部分が展開されて、次のように処理されることになります。
zip(('Sato', 70), ('Tanaka', 80), ('Yamada', 90))
zipの引数それぞれの2番目の要素(名前)、2番目の要素(スコア)がまとめられるので、確かにunzipに相当する動きをすることが確認できます。
参考サイト:
pythonでzip、unzip - Qiita
アスタリスクによるシーケンスの展開 - or1ko's diary