Как преобразовать кортеж кортежей в одномерный список, используя понимание списка? [дубликат]
этот вопрос уже есть ответ здесь:
у меня есть кортеж кортежей, например:
tupleOfTuples = ((1, 2), (3, 4), (5,))
Я хочу преобразовать это в плоский, одномерный список всех элементов по порядку:
[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]
... но это не сработало. Есть идеи? Или я должен просто придерживаться цикла?
7 ответов
обычно это называется сплющиванием вложенной структуры.
>>> 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
ПВП: пожалуйста, не используйте tuple
как имя переменной, он теней встроенный.
просто использовать 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
.
микро-ориентиры:
-
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
-
короткий кортеж длиной кортежи!--11-->
$ 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))
быстрее, если внешний кортеж длинный.
вы сковываете кортежи вместе:
from itertools import chain
print list(chain(*listOfTuples))
должно быть довольно читаемым, если вы знакомы с itertools
, и без явного list
у вас даже есть результат в форме генератора.
большинство из этих ответов будет работать только для одного уровня уплощения. Для более полного решения попробуйте это (от 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)
Мне нравится использовать "уменьшить" в этой ситуации (это то, для чего сделано сокращение!)
lot = ((1, 2), (3, 4), (5,))
print list(reduce(lambda t1, t2: t1 + t2, lot))
> [1,2,3,4,5]
для многоуровневого и читаемого кода:
def flatten(bla):
output = []
for item in bla:
output += flatten(item) if hasattr (item, "__iter__") or hasattr (item, "__len__") else [item]
return output
Я не мог заставить это поместиться в одну строку (и оставаться читаемым, даже на сегодняшний день)
другое решение с использованием itertools.цепь
>>> tupleOfTuples = ((1, 2), (3, 4), (5,))
>>> from itertools import chain
>>> [x for x in chain.from_iterable(tupleOfTuples)]
[1, 2, 3, 4, 5]