2 項目のタプルのリストがあり、最初のリストに各タプルの最初の項目が含まれ、2 番目のリストに 2 番目の項目が含まれる 2 つのリストに変換したいと考えています。
例えば:
original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
# and I want to become...
result = (['a', 'b', 'c', 'd'], [1, 2, 3, 4])
それを行う組み込み関数はありますか?
zip
は独自の逆です。特殊な * 演算子を使用する場合。
>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)])
[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
zip
これが機能する方法は、引数を指定して呼び出すことです。
zip(('a', 1), ('b', 2), ('c', 3), ('d', 4))
…引数が直接 (タプルに変換された後に) に渡されることを除けば、引数zip
の数が大きくなりすぎることを心配する必要はありません。
あなたもできる
result = ([ a for a,b in original ], [ b for a,b in original ])
より適切にスケーリングする必要があります。特に Python が、必要な場合を除いてリスト内包表記を展開しないことに長けている場合。
(ちなみに、これはタプルのリストではなく、リストの 2 タプル (ペア) を作成zip
します。)
実際のリストの代わりにジェネレーターが問題ない場合は、次のようになります。
result = (( a for a,b in original ), ( b for a,b in original ))
ジェネレーターは、ユーザーが各要素を要求するまでリストをくまなく調べませんが、一方で、元のリストへの参照を保持します。
zip(*iterable)
私は自分のプログラムで(あなたが探しているコードの一部です)を次のように使用するのが好きです:
def unzip(iterable):
return zip(*iterable)
unzip
もっと読みやすいと思います。
長さが同じでないリストがある場合は、パトリックの回答に従って zip を使用したくない場合があります。これは機能します:
>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)])
[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
しかし、リストの長さが異なる場合、zip は各項目を最短のリストの長さに切り詰めます。
>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', )])
[('a', 'b', 'c', 'd', 'e')]
関数なしで map を使用して、空の結果を None で埋めることができます。
>>> map(None, *[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', )])
[('a', 'b', 'c', 'd', 'e'), (1, 2, 3, 4, None)]
ただし、zip() はわずかに高速です。
>>> original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
>>> tuple([list(tup) for tup in zip(*original)])
(['a', 'b', 'c', 'd'], [1, 2, 3, 4])
質問のようにリストのタプルを提供します。
list1, list2 = [list(tup) for tup in zip(*original)]
2 つのリストをアンパックします。
それはそれを行う別の方法にすぎませんが、それは私を大いに助けたので、ここに書きます:
このデータ構造を持つ:
X=[1,2,3,4]
Y=['a','b','c','d']
XY=zip(X,Y)
その結果:
In: XY
Out: [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]
私の意見では、それを解凍して元に戻すためのよりpythonicな方法は次のとおりです。
x,y=zip(*XY)
ただし、これはタプルを返すため、リストが必要な場合は次を使用できます。
x,y=(list(x),list(y))