Как сделать плоский список из списка списков - PullRequest
2641 голосов
/ 05 июня 2009

Интересно, есть ли ярлык для создания простого списка из списка списков в Python.

Я могу сделать это в цикле for, но, может быть, есть какой-нибудь крутой "однострочный"? Я пробовал с уменьшить , но я получаю ошибку.

Код

l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
reduce(lambda x, y: x.extend(y), l)

Сообщение об ошибке

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
AttributeError: 'NoneType' object has no attribute 'extend'

Ответы [ 39 ]

19 голосов
/ 02 декабря 2016

Рассмотрите возможность установки пакета more_itertools.

> pip install more_itertools

Поставляется с реализацией для flatten ( источник , из рецептов itertools ):

import more_itertools


lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(more_itertools.flatten(lst))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

Начиная с версии 2.4, вы можете выровнять более сложные вложенные итерации с помощью more_itertools.collapse ( источник , предоставленный abarnet).

lst = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
list(more_itertools.collapse(lst)) 
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

lst = [[1, 2, 3], [[4, 5, 6]], [[[7]]], 8, 9]              # complex nesting
list(more_itertools.collapse(lst))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
18 голосов
/ 05 июня 2009

Причина, по которой ваша функция не работает: расширение расширяет массив на месте и не возвращает его. Вы все еще можете вернуть x из лямбды, используя некоторый трюк:

reduce(lambda x,y: x.extend(y) or x, l)

Примечание: расширение более эффективно, чем + в списках.

13 голосов
/ 26 октября 2016
def flatten(l, a):
    for i in l:
        if isinstance(i, list):
            flatten(i, a)
        else:
            a.append(i)
    return a

print(flatten([[[1, [1,1, [3, [4,5,]]]], 2, 3], [4, 5],6], []))

# [1, 1, 1, 3, 4, 5, 2, 3, 4, 5, 6]
12 голосов
/ 11 ноября 2016

Плохая особенность функции Анила, описанной выше, заключается в том, что пользователь всегда должен вручную указывать второй аргумент как пустой список []. Вместо этого это должно быть по умолчанию. Из-за того, как работают объекты Python, их следует устанавливать внутри функции, а не в аргументах.

Вот рабочая функция:

def list_flatten(l, a=None):
    #check a
    if a is None:
        #initialize with empty list
        a = []

    for i in l:
        if isinstance(i, list):
            list_flatten(i, a)
        else:
            a.append(i)
    return a

Тестирование:

In [2]: lst = [1, 2, [3], [[4]],[5,[6]]]

In [3]: lst
Out[3]: [1, 2, [3], [[4]], [5, [6]]]

In [11]: list_flatten(lst)
Out[11]: [1, 2, 3, 4, 5, 6]
11 голосов
/ 24 сентября 2018

Принятый ответ не работал для меня при работе с текстовыми списками переменной длины. Вот альтернативный подход, который работал для меня.

l = ['aaa', 'bb', 'cccccc', ['xx', 'yyyyyyy']]

Принятый ответ, который не работает:

flat_list = [item for sublist in l for item in sublist]
print(flat_list)
['a', 'a', 'a', 'b', 'b', 'c', 'c', 'c', 'c', 'c', 'c', 'xx', 'yyyyyyy']

Новое предлагаемое решение, которое сработало для меня:

flat_list = []
_ = [flat_list.extend(item) if isinstance(item, list) else flat_list.append(item) for item in l if item]
print(flat_list)
['aaa', 'bb', 'cccccc', 'xx', 'yyyyyyy']
10 голосов
/ 01 февраля 2018

matplotlib.cbook.flatten() будет работать для вложенных списков, даже если они вложены глубже, чем в примере.

import matplotlib
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
print(list(matplotlib.cbook.flatten(l)))
l2 = [[1, 2, 3], [4, 5, 6], [7], [8, [9, 10, [11, 12, [13]]]]]
print list(matplotlib.cbook.flatten(l2))

Результат:

[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

Это в 18 раз быстрее, чем подчеркивание ._. Flatten:

Average time over 1000 trials of matplotlib.cbook.flatten: 2.55e-05 sec
Average time over 1000 trials of underscore._.flatten: 4.63e-04 sec
(time for underscore._)/(time for matplotlib.cbook) = 18.1233394636
9 голосов
/ 05 июля 2017

Следующие мне кажутся простейшими:

>>> import numpy as np
>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> print (np.concatenate(l))
[1 2 3 4 5 6 7 8 9]
8 голосов
/ 17 июля 2016

Можно также использовать NumPy's flat :

import numpy as np
list(np.array(l).flat)

Редактировать 02.11.2016: Работает только в том случае, если подсписки имеют одинаковые размеры.

6 голосов
/ 14 декабря 2018

Рекурсивная версия

x = [1,2,[3,4],[5,[6,[7]]],8,9,[10]]

def flatten_list(k):
    result = list()
    for i in k:
        if isinstance(i,list):

            #The isinstance() function checks if the object (first argument) is an 
            #instance or subclass of classinfo class (second argument)

            result.extend(flatten_list(i)) #Recursive call
        else:
            result.append(i)
    return result

flatten_list(x)
#result = [1,2,3,4,5,6,7,8,9,10]
6 голосов
/ 24 июля 2018

Вы можете использовать numpy:
flat_list = list(np.concatenate(list_of_list))

...