Python : zip()は複数のイテラブルを受け取りタプルで返す

TwitterFacebookHatena
  • 公開:2021-8-31
  • 更新:2023-10-26
  • 文章量:1885
  • Python

TL;DR

zip()は複数のイテラブルを受け取り、タプルで返す。zip(*[iter(s)]*n) を使うことでイテラブルを分割することができる。

zip() のポイント

  • 複数のイテラブルからイテレータを作る
  • イテラブルの中で最短のものが尽きると停止する
  • zip(*[iter(s)]*n) でイテラブルを分割することができる
  • 余りを表示するには zip_longest()関数をインポートする
a = zip('ABCD', '12')
list(a)

# [('A', '1'), ('B', '2')]

複数のリスト

複数のリストを適用すると、最も短いイテラブルの数で停止する。

x = [1,2,3]
y = [4,5,6,7]
z = [8,9] # → 一番短いイテラブル

list(zip(x,y,z))
# [(1, 4, 8), (2, 5, 9)]

for 文 で使う

もちろん、for 文で使うこともできる。

a = [1, 2, 3, 4]
b = ['A', 'B']
c = ['い', 'ろ', 'は']

for a, b, c in zip(a, b, c):
    print(a, b, c)

# 1 A い
# 2 B ろ

イテラブルを分割する

zip(*[iter(s)]*n) を使えば、イテラブルを n 回分割することができる。

b = [1, 2, 3, 4, 5, 6, 7]
c = zip(*[iter(b)]*2)

list(c)

# [(1, 2), (3, 4), (5, 6)]

中身を見てみると、同じイテレータを参照している。

b = [1, 2, 3, 4, 5, 6, 7]
[iter(b)]*2

# [<list_iterator at 0x7f7eab2ad790>,
#  <list_iterator at 0x7f7eab2ad790>]

公式サイトには以下のように書かれている。

zip(*[iter(s)]*n) を使ってデータ系列を長さ n のグループにクラスタリング(グループ分け)するイディオム(慣用表現)が使えます。これは、各出力タプルがイテレータを n 回呼び出した結果となるよう、 同じ イテレータを n 回繰り返します。これは入力を長さ n のチャンクに分割する効果があります。 組み込み関数 — Python 3.9.4 ドキュメント

しかし、なぜこうなるのか?

iterator-zip(_ [iter(s)] _ n)は Python でどのように機能しますか? - スタックオーバーフローに解説があった。例えば以下の場合、

s = [1,2,3,4,5,6,7,8,9]
n = 3

list(zip(*[iter(s)]*n))

# [(1, 2, 3), (4, 5, 6), (7, 8, 9)]

上を展開すると以下になる。同じイテレータを 3 回渡すと、zip()されるたびにイテレータからアイテムがプルされる。なお、余りは捨てられる。

s = iter([1,2,3,4,5,6,7,8,9])
list(zip(s, s, s))

# [(1, 2, 3), (4, 5, 6), (7, 8, 9)]

zip_longest():一番長いイテラブルを出力

余りを表示するには、intertools.zip_longest()関数をインポートするとよい。一番長いイテラブルに合わせることができる。

from itertools import zip_longest

b = [1, 2, 3, 4, 5, 6, 7]
c = zip_longest(*[iter(b)]*2)

list(c)

# [(1, 2), (3, 4), (5, 6), (7, None)]

fillvalue:任意の値で埋める

None 以外の値で埋めたいときは、どうすればいいのか?引数に fillvalue を指定することで、任意の値で埋めることができる。

from itertools import zip_longest
x = [1,2,3]
y = [4,5,6,7]
z = [8,9]

list(zip_longest(x, y, z, fillvalue=100))

# [(1, 4, 8), (2, 5, 9), (3, 6, 100), (100, 7, 100)]

Python : zip()は複数のイテラブルを受け取りタプルで返す