今日も窓辺でプログラム

外資系企業勤めのエンジニアが勉強した内容をまとめておくブログ

Pythonでunzipってどうやるの?

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