Как сделать плоский список из списка списков

Не думаю, что это возможно. Мне не удалось найти документацию, в которой это явно указано, но я считаю, что go test всегда использует каталог пакетов (содержащий исходные исходные файлы) в качестве рабочего каталога.

2786
задан Peter Mortensen 12 April 2019 в 11:04
поделиться

13 ответов

Дан список списков l ,

flat_list = [элемент для подсписка в l для элемента в подсписке]

, что означает:

flat_list = []
for sublist in l:
    for item in sublist:
        flat_list.append(item)

быстрее чем ярлыки, опубликованные до сих пор. ( l - список, который необходимо сгладить.)

Вот соответствующая функция:

flatten = lambda l: [item for sublist in l for item in sublist]

В качестве доказательства вы можете использовать модуль timeit в стандартной библиотеке:

$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in l for item in sublist]'
10000 loops, best of 3: 143 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 969 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 3: 1.1 msec per loop

Объяснение: ярлыки, основанные на + (включая подразумеваемое использование в sum ), по необходимости, являются O (L ** 2) , когда есть L подсписок - по мере того, как список промежуточных результатов становится длиннее, на каждом шаге выделяется новый объект списка промежуточных результатов, и все элементы в предыдущем промежуточном результате должны быть скопированы (а также несколько новых добавляются в конце). Итак, для простоты и без потери общности, скажем, у вас есть L подсписок по I элементов в каждом: первые I элементов копируются взад и вперед L-1 раз, вторые I-элементы L-2 раза и так далее; общее количество копий в I раз больше суммы x для x от 1 до L исключено, то есть I * (L ** 2) / 2 .

Компонент списка генерирует только один список один раз , и копирует каждый элемент (из исходного места жительства в список результатов) также ровно один раз.

4233
ответ дан 22 November 2019 в 19:47
поделиться

другой интересный способ сделать это:

from functools import reduce
from operator import add

li=[[1,2],[3,4]]
x= reduce(add, li)
1
ответ дан sudeepgupta90 14 September 2019 в 15:56
поделиться

Не изобретайте велосипед, если Вы используете Django:

>>> from django.contrib.admin.utils import flatten
>>> l = [[1,2,3], [4,5], [6]]
>>> flatten(l)
>>> [1, 2, 3, 4, 5, 6]

... Панды :

>>> from pandas.core.common import flatten
>>> list(flatten(l))

... Itertools:

>>> import itertools
>>> flatten = itertools.chain.from_iterable
>>> list(flatten(l))

... Matplotlib

>>> from matplotlib.cbook import flatten
>>> list(flatten(l))

... Unipath:

>>> from unipath.path import flatten
>>> list(flatten(l))

... Setuptools:

>>> from setuptools.namespaces import flatten
>>> list(flatten(l))
35
ответ дан 22 November 2019 в 19:47
поделиться
from nltk import flatten

l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
flatten(l)

преимущество этого решения по большинству других здесь - это, если у Вас есть список как:

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

, в то время как большинство других решений бросает ошибку, это решение обрабатывает их.

4
ответ дан 22 November 2019 в 19:47
поделиться

Почему вы используете расширение?

reduce(lambda x, y: x+y, l)

Это должно работать нормально.

31
ответ дан 22 November 2019 в 19:47
поделиться

Примечание автора : Это неэффективно. Но весело, потому что моноиды потрясающие. Это не подходит для производственного кода Python.

>>> sum(l, [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Это просто суммирует элементы итерации, переданные в первом аргументе, обрабатывая второй аргумент как начальное значение суммы (если не указано, вместо него используется 0 , и в этом случае будет выдана ошибка) .

Поскольку вы суммируете вложенные списки, вы фактически получаете [1,3] + [2,4] как результат sum ([[1,3], [2, 4]], []) , что равно [1,3,2,4] .

Обратите внимание, что работает только со списками списков. Для списков списков списков вам понадобится другое решение.

[]) , что равно [1,3,2,4] .

Обратите внимание, что работает только со списками списков. Для списков списков списков вам понадобится другое решение.

[]) , что равно [1,3,2,4] .

Обратите внимание, что работает только со списками списков. Для списков списков списков вам понадобится другое решение.

816
ответ дан 22 November 2019 в 19:47
поделиться
from functools import reduce #python 3

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

Метод extend () в вашем примере изменяет x вместо того, чтобы возвращать полезное значение (которое reduce () ожидает

Более быстрый способ выполнить версию reduce - это

>>> import operator
>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(operator.concat, l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
157
ответ дан 22 November 2019 в 19:47
поделиться

Причина, по которой ваша функция не работает, заключается в том, что extension расширяет массив в- место и не возвращает.

20
ответ дан 22 November 2019 в 19:47
поделиться

Беру свое заявление обратно. сумма не является победителем. Хотя быстрее, когда список невелик. Но производительность значительно снижается с большими списками.

>>> timeit.Timer(
        '[item for sublist in l for item in sublist]',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10000'
    ).timeit(100)
2.0440959930419922

Суммарная версия все еще работает более минуты и еще не обработана!

Для средних списков:

>>> timeit.Timer(
        '[item for sublist in l for item in sublist]',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
    ).timeit()
20.126545906066895
>>> timeit.Timer(
        'reduce(lambda x,y: x+y,l)',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
    ).timeit()
22.242258071899414
>>> timeit.Timer(
        'sum(l, [])',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]] * 10'
    ).timeit()
16.449732065200806

Использование небольших списков и timeit: number = 1000000

>>> timeit.Timer(
        '[item for sublist in l for item in sublist]',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
    ).timeit()
2.4598159790039062
>>> timeit.Timer(
        'reduce(lambda x,y: x+y,l)',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
    ).timeit()
1.5289170742034912
>>> timeit.Timer(
        'sum(l, [])',
        'l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]'
    ).timeit()
1.0598428249359131
37
ответ дан 22 November 2019 в 19:47
поделиться

Вы можете использовать itertools.chain () :

>>> import itertools
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain(*list2d))

или, в Python> = 2.6, использовать itertools.chain.from_iterable () который не требует распаковки списка:

>>> import itertools
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain.from_iterable(list2d))

Этот подход, возможно, более читабелен, чем [элемент для подсписка в l для элемента в подсписке] , и, похоже, тоже быстрее:

[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99;import itertools' 'list(itertools.chain.from_iterable(l))'
10000 loops, best of 3: 24.2 usec per loop
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in l for item in sublist]'
10000 loops, best of 3: 45.2 usec per loop
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 488 usec per loop
[me@home]$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 3: 522 usec per loop
[me@home]$ python --version
Python 2.7.3
1380
ответ дан 22 November 2019 в 19:47
поделиться

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

def flatten(nested_lst):
    """ Return a list after transforming the inner lists
        so that it's a 1-D list.

    >>> flatten([[[],["a"],"a"],[["ab"],[],"abc"]])
    ['a', 'a', 'ab', 'abc']
    """
    if not isinstance(nested_lst, list):
        return(nested_lst)

    res = []
    for l in nested_lst:
        if not isinstance(l, list):
            res += [l]
        else:
            res += flatten(l)


    return(res)

>>> flatten([[[],["a"],"a"],[["ab"],[],"abc"]])
['a', 'a', 'ab', 'abc']
-1
ответ дан 22 November 2019 в 19:47
поделиться

Одна строка мы используем + к спискам concat с обработкой None, 'hello'

import functools
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9],None,'hello']

functools.reduce(lambda acc,x: x + acc if isinstance(x,list) else acc + [x] ,l,[])
0
ответ дан 22 November 2019 в 19:47
поделиться

Одна возможность состоит в том, чтобы рассматривать массив как строку:

elements = [[180.0, 1, 2, 3], [173.8], [164.2], [156.5], [147.2], [138.2]]
list(map(float, str(elements).replace("[", "").replace("]", "").split(",")))
0
ответ дан 22 November 2019 в 19:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: