web-dev-qa-db-ja.com

リスト内包表記を使用して、タプルのタプルを1次元リストに変換するにはどうすればよいですか?

タプルのタプルがあります-例えば:

_tupleOfTuples = ((1, 2), (3, 4), (5,))
_

これを、すべての要素を順番に並べたフラットな1次元リストに変換します。

_[1, 2, 3, 4, 5]
_

私はリストを理解してこれを達成しようとしています。しかし、私はそれを理解できないようです。 for-eachループでそれを達成できました。

_myList = []
for Tuple in tupleOfTuples:
   myList = myList + list(Tuple)
_

しかし、リストを理解してこれを行う方法があるに違いないと感じています。

単純な[list(Tuple) for Tuple in tupleOfTuples]は、個々の要素ではなく、リストのリストを提供するだけです。次のように、アンパック演算子を使用してリストをアンパックすることで、おそらくこれに基づいて構築できると思いました。

_[*list(Tuple) for Tuple in tupleOfTuples]
_

または

_[*(list(Tuple)) for Tuple in tupleOfTuples]
_

...しかし、それはうまくいきませんでした。何か案は?それとも、ループに固執する必要がありますか?

30
froadie

通常、ネスト構造のフラット化と呼ばれます。

>>> tupleOfTuples = ((1, 2), (3, 4), (5,))
>>> [element for tupl in tupleOfTuples for element in tupl]
[1, 2, 3, 4, 5]

効率を示すためだけに:

>>> import timeit
>>> it = lambda: list(chain(*tupleOfTuples))
>>> timeit.timeit(it)
2.1475738355700913
>>> lc = lambda: [element for tupl in tupleOfTuples for element in tupl]
>>> timeit.timeit(lc)
1.5745135182887857

[〜#〜] eta [〜#〜]Tupleを変数名として使用しないでください。ビルトインをシャドーします。

61
SilentGhost

タプルが多くない場合は、sumを使用します。

_>>> tupleOfTuples = ((1, 2), (3, 4), (5,))
>>> sum(tupleOfTuples, ())
(1, 2, 3, 4, 5)
>>> list(sum(tupleOfTuples, ())) # if you really need a list
[1, 2, 3, 4, 5]
_

タプルがたくさんある場合は、 リスト内包表記 または _chain.from_iterable_ を使用して、sumの2次的な動作を防ぎます。


マイクロベンチマーク:

  • Python 2.6

    • 短いタプルの長いタプル

      _$ python2.6 -m timeit -s 'tot = ((1, 2), )*500' '[element for tupl in tot for element in tupl]'
      10000 loops, best of 3: 134 usec per loop
      $ python2.6 -m timeit -s 'tot = ((1, 2), )*500' 'list(sum(tot, ()))'
      1000 loops, best of 3: 1.1 msec per loop
      $ python2.6 -m timeit -s 'tot = ((1, 2), )*500; from itertools import chain; ci = chain.from_iterable' 'list(ci(tot))'
      10000 loops, best of 3: 60.1 usec per loop
      $ python2.6 -m timeit -s 'tot = ((1, 2), )*500; from itertools import chain' 'list(chain(*tot))'
      10000 loops, best of 3: 64.8 usec per loop
      _
    • 長いタプルの短いタプル

      _$ python2.6 -m timeit -s 'tot = ((1, )*500, (2, )*500)' '[element for tupl in tot for element in tupl]'
      10000 loops, best of 3: 65.6 usec per loop
      $ python2.6 -m timeit -s 'tot = ((1, )*500, (2, )*500)' 'list(sum(tot, ()))'
      100000 loops, best of 3: 16.9 usec per loop
      $ python2.6 -m timeit -s 'tot = ((1, )*500, (2, )*500); from itertools import chain; ci = chain.from_iterable' 'list(ci(tot))'
      10000 loops, best of 3: 25.8 usec per loop
      $ python2.6 -m timeit -s 'tot = ((1, )*500, (2, )*500); from itertools import chain' 'list(chain(*tot))'
      10000 loops, best of 3: 26.5 usec per loop
      _
  • Python 3.1

    • 短いタプルの長いタプル

      _$ python3.1 -m timeit -s 'tot = ((1, 2), )*500' '[element for tupl in tot for element in tupl]'
      10000 loops, best of 3: 121 usec per loop
      $ python3.1 -m timeit -s 'tot = ((1, 2), )*500' 'list(sum(tot, ()))'
      1000 loops, best of 3: 1.09 msec per loop
      $ python3.1 -m timeit -s 'tot = ((1, 2), )*500; from itertools import chain; ci = chain.from_iterable' 'list(ci(tot))'
      10000 loops, best of 3: 59.5 usec per loop
      $ python3.1 -m timeit -s 'tot = ((1, 2), )*500; from itertools import chain' 'list(chain(*tot))'
      10000 loops, best of 3: 63.2 usec per loop
      _
    • 長いタプルの短いタプル

      _$ python3.1 -m timeit -s 'tot = ((1, )*500, (2, )*500)' '[element for tupl in tot for element in tupl]'
      10000 loops, best of 3: 66.1 usec per loop
      $ python3.1 -m timeit -s 'tot = ((1, )*500, (2, )*500)' 'list(sum(tot, ()))'
      100000 loops, best of 3: 16.3 usec per loop
      $ python3.1 -m timeit -s 'tot = ((1, )*500, (2, )*500); from itertools import chain; ci = chain.from_iterable' 'list(ci(tot))'
      10000 loops, best of 3: 25.4 usec per loop
      $ python3.1 -m timeit -s 'tot = ((1, )*500, (2, )*500); from itertools import chain' 'list(chain(*tot))'
      10000 loops, best of 3: 25.6 usec per loop
      _

観察:

  • 外側のタプルが短い場合、sumは高速です。
  • 外側のタプルが長い場合、list(chain.from_iterable(x))は高速です。
39
kennytm

タプルを一緒にチェーンしています:

from itertools import chain
print list(chain(*listOfTuples))

itertoolsに精通していればかなり読みやすく、明示的なlistがなければ、結果はジェネレーター形式でもあります。

10
Jochen Ritzel

これらの回答のほとんどは、単一レベルのフラット化に対してのみ機能します。より包括的なソリューションについては、これを試してください( http://rightfootin.blogspot.com/2006/09/more-on-python-flatten.html から):

def flatten(l, ltypes=(list, Tuple)):
    ltype = type(l)
    l = list(l)
    i = 0
    while i < len(l):
        while isinstance(l[i], ltypes):
            if not l[i]:
                l.pop(i)
                i -= 1
                break
            else:
                l[i:i + 1] = l[i]
        i += 1
    return ltype(l)
9
Craig Trader

私はこの状況で 'reduce'を使用するのが好きです(これがreduceの目的です!)

lot = ((1, 2), (3, 4), (5,))
print list(reduce(lambda t1, t2: t1 + t2, lot))

 > [1,2,3,4,5]
8
Donald Miner

マルチレベルで読み取り可能なコードの場合:

def flatten(bla):
    output = []
    for item in bla:
        output += flatten(item) if hasattr (item, "__iter__") or hasattr (item, "__len__") else [item]
    return output

これを1行に収めることができませんでした

4
jsbueno

itertools.chain を使用する別のソリューション

>>> tupleOfTuples = ((1, 2), (3, 4), (5,))
>>> from itertools import chain
>>> [x for x in chain.from_iterable(tupleOfTuples)]
[1, 2, 3, 4, 5]
1
Mad Scientist