36

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

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]

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

4

7 に答える 7

73

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

>>> 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。組み込みを隠します。

于 2010-07-08T13:54:54.140 に答える
45

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、 の 2 次動作を防ぎsumます。


マイクロベンチマーク:

  • パイソン 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
      
  • パイソン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))外側のタプルが長い場合は高速です。
于 2010-07-08T15:55:56.330 に答える
13

タプルをつなぎ合わせています。

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

に精通している場合はかなり読みやすいはずです。itertools明示的でlistない場合は、ジェネレータ形式で結果を取得することもできます。

于 2010-07-08T14:07:16.240 に答える
9

これらの回答のほとんどは、単一レベルの平坦化に対してのみ機能します。より包括的な解決策については、これを試してください(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)
于 2010-07-08T14:15:17.360 に答える
9

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

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

 > [1,2,3,4,5]
于 2010-07-08T13:58:38.753 に答える
4

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]
于 2010-07-08T14:07:28.817 に答える
4

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

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

これを1行に収めることができませんでした(そして、はるかに読みやすいままです)

于 2010-07-08T15:52:27.580 に答える