Преобразуйте «список кортежей» в плоский список или матрицу

82

В Sqlite команда «select..from» возвращает результат «output», который печатает (в python):

>>print output
[(12.2817, 12.2817), (0, 0), (8.52, 8.52)]

Кажется, это список кортежей. Я хотел бы либо преобразовать «вывод» в простой одномерный массив (я думаю, это список в Python):

[12.2817, 12.2817, 0, 0, 8.52, 8.52]

или матрица 2x3:

12.2817 12.2817
0          0 
8.52     8.52

для чтения через "output [i] [j]"

Команда flatten не работает для первого варианта, а второй я понятия не имею ... :)

Не могли бы вы мне намекнуть? Что-то быстрое было бы замечательно, поскольку реальные данные намного больше (вот только простой пример).

сад
источник
2
[(12.2817, 12.2817), (0, 0), (8.52, 8.52)]это уже матрица 3х2 !? или я что-то упустил?
mouad
См. Этот вопрос
Джоэл Корнетт
1
для рецептов модуля itertools проверки функции flatten уже есть пример функции flatten
mouad
4
[item for sublist in output for item in sublist]отлично работает и имеет то преимущество, что ваши внутренние кортежи также могут быть списками; в общем, любая комбинация внутренних и внешних повторяемых работ
Кисс Тао

Ответы:

125

Безусловно, самое быстрое (и самое короткое) решение опубликовано:

list(sum(output, ()))

Примерно на 50% быстрее, чем itertoolsраствор, и примерно на 70% быстрее, чем mapраствор.

Джоэл Корнетт
источник
8
@ Джоэл хороший, но мне интересно, как это работает? list(output[0]+output[1]+output[2])дает желаемый результат но list(sum(output))нет. Почему? Какое «волшебство» делает ()?
Kyss Tao
9
Хорошо, я должен был прочитать руководство g . Кажется sum(sequence[, start]): сумма добавляет, startкоторый по умолчанию, 0а не просто начиная с, sequence[0]если он существует, а затем добавляет остальные элементы. Извините за беспокойство.
Kyss Tao
3
Это хорошо известный антипаттерн: не используйте sumдля объединения последовательностей, это приводит к квадратичному алгоритму времени. Действительно, sumфункция будет жаловаться, если вы попытаетесь сделать это со строками!
juanpa.arrivillaga
@ juanpa.arrivillaga: согласен. Очень мало вариантов использования, где это было бы предпочтительнее.
Джоэл Корнетт
9
Да, быстро, но совершенно тупо. Вы должны оставить комментарий о том, что он на самом деле делает :(
CpILL
42

Подход к пониманию списка, который работает с итерабельными типами и работает быстрее, чем другие методы, показанные здесь.

flattened = [item for sublist in l for item in sublist]

lсписок для сглаживания (вызывается в outputслучае OP)


timeit тесты:

l = list(zip(range(99), range(99)))  # list of tuples to flatten

Понимание списка

[item for sublist in l for item in sublist]

timeit result = 7,67 мкс ± 129 нс на цикл

Список метод расширения ()

flattened = []
list(flattened.extend(item) for item in l)

timeit result = 11 мкс ± 433 нс на цикл

сумма ()

list(sum(l, ()))

timeit result = 24,2 мкс ± 269 нс на цикл

Gman
источник
1
Мне пришлось использовать это на большом наборе данных, метод понимания списка был самым быстрым!
nbeuchat
Я немного изменил решение .extend, и теперь он работает немного лучше. проверьте это в удобное для вас времяит для сравнения
Тоторо
24

В Python 2.7 и во всех версиях Python3 вы можете использовать itertools.chainдля сглаживания списка итераций. Либо с *синтаксисом, либо с методом класса.

>>> t = [ (1,2), (3,4), (5,6) ]
>>> t
[(1, 2), (3, 4), (5, 6)]
>>> import itertools
>>> list(itertools.chain(*t))
[1, 2, 3, 4, 5, 6]
>>> list(itertools.chain.from_iterable(t))
[1, 2, 3, 4, 5, 6]
Thruston
источник
11

Обновление : сглаживание с использованием расширения, но без понимания и без использования списка в качестве итератора (самый быстрый)

После проверки следующего ответа на этот вопрос, который обеспечил более быстрое решение через понимание списка, dual forя немного подправил, и теперь он работает лучше, сначала выполнение list (...) перетаскивало большой процент времени, а затем меняло список понимание простой петли также побрило немного больше.

Новое решение:

l = []
for row in output: l.extend(row)

Старший:

Сглаживание с картой / расширением:

l = []
list(map(l.extend, output))

Сглаживание с пониманием списка вместо карты

l = []
list(l.extend(row) for row in output)

некоторое время для нового расширения и улучшения, полученного путем простого удаления списка (...) для [...]:

import timeit
t = timeit.timeit
o = "output=list(zip(range(1000000000), range(10000000))); l=[]"
steps_ext = "for row in output: l.extend(row)"
steps_ext_old = "list(l.extend(row) for row in output)"
steps_ext_remove_list = "[l.extend(row) for row in output]"
steps_com = "[item for sublist in output for item in sublist]"

print("new extend:      ", t(steps_ext, setup=o, number=10))
print("old extend w []: ", t(steps_ext_remove_list, setup=o, number=10))
print("comprehension:   ", t(steps_com, setup=o, number=10,))
print("old extend:      ", t(steps_ext_old, setup=o, number=10))

>>> new extend:       4.502427191007882
>>> old extend w []:  5.281140706967562
>>> comprehension:    5.54302118299529
>>> old extend:       6.840151469223201    
Тоторо
источник
9

использовать itertoolsцепочку:

>>> import itertools
>>> list(itertools.chain.from_iterable([(12.2817, 12.2817), (0, 0), (8.52, 8.52)]))
[12.2817, 12.2817, 0, 0, 8.52, 8.52]
Чарльз Битти
источник
7
>>> flat_list = []
>>> nested_list = [(1, 2, 4), (0, 9)]
>>> for a_tuple in nested_list:
...     flat_list.extend(list(a_tuple))
... 
>>> flat_list
[1, 2, 4, 0, 9]
>>> 

вы можете легко перейти от списка кортежей к одному списку, как показано выше.

Коби
источник
7

Или вы можете сгладить список следующим образом:

reduce(lambda x,y:x+y, map(list, output))
Мария Зверина
источник
reduce(lambda x,y:x+y, output)похоже, работает с прямым преобразованием в длинный кортеж (который можно преобразовать в список). Зачем использовать map(list, output)внутри reduce()звонка? Возможно, это больше соответствует тому факту, что кортежи неизменяемы, списки изменяемы .
Paul Rougieux
5

Это то, numpyдля чего было сделано, как с точки зрения структур данных, так и с точки зрения скорости.

import numpy as np

output = [(12.2817, 12.2817), (0, 0), (8.52, 8.52)]
output_ary = np.array(output)   # this is your matrix 
output_vec = output_ary.ravel() # this is your 1d-array
Джошуа Кук
источник
2

В случае произвольных вложенных списков (на всякий случай):

def flatten(lst):
    result = []
    for element in lst: 
        if hasattr(element, '__iter__'):
            result.extend(flatten(element))
        else:
            result.append(element)
    return result

>>> flatten(output)
[12.2817, 12.2817, 0, 0, 8.52, 8.52]
cval
источник