2015/02/10

Python Tips:複数のリストに対してループを回したい

Pythonで複数のリストに対してループを同時に回す方法をご紹介します。

最もシンプルなのは zip 関数を使う方法です。

さっそく例を見てみます。まず最初は同じ長さのふたつのリストの場合。
li1 = [1, 2, 3]
li2 = [11, 12, 13]
zip(li1, li2)
# => [(1, 11), (2, 12), (3, 13)]
戻り値は各要素をペアにしたタプルのリストとなります。

リストの長さが異なる場合は短い方のリストに合わせられます。
li1 = [1, 2, 3, 4, 5]
li2 = [11, 12, 13]
zip(li1, li2)
# => [(1, 11), (2, 12), (3, 13)]

みっつ以上のリストの場合もふたつの場合と同じようにまとめてくれます。
li1 = [1, 2, 3]
li2 = [11, 12, 13]
li3 = ['a', 'b', 'c']
zip(li1, li2, li3)
# => [(1, 11, 'a'), (2, 12, 'b'), (3, 13, 'c')]

逆にリストがひとつの場合も例外をあげることなく動作してくれます。
li1 = [1, 2, 3]
zip(li1)
# => [(1,), (2,), (3,)]


生成される合成リストの長さを最短のリストではなく最長のリストに合わせたい場合は itertools.zip_longest を使うのが便利です。
import itertools

li1 = [1, 2, 3, 4, 5]
li2 = [11, 12, 13]
print([x for x in itertools.zip_longest(li1, li2)])
# => [(1, 11), (2, 12), (3, 13), (None, 14), (None, 15)]


以上です。

ちなみに組み込みの zip と同じような処理を自分で書くとすると次のような形になるかと思います。
def myzip(*lists):
    """組み込みの zip と同じ処理をする関数 myzip """
    i = 0
    combined = []
    while True:
        try:
            # 各リストの同じインデックスの要素をタプルにまとめて追加
            # インデックスがどれかひとつの要素の長さを越えれば break
            e = []
            for li in lists:
                e.append(li[i])
            combined.append(tuple(e))
            i += 1
        except IndexError:
            break
    return combined

またまたちなみに、Python3では zip 関数はリストではなくイテレータを返す形に変更されています。


参考
iterator - how can I iterate through two lists in parallel in Python? - Stack Overflow


0 件のコメント: