Подтвердить что ты не робот

Как сгладить 2D-список до 1D без использования numpy?

У меня есть список, который выглядит следующим образом:

[[1,2,3],[1,2],[1,4,5,6,7]]

и я хочу сгладить его в [1,2,3,1,2,1,4,5,6,7]

есть ли легкая функция для этого, не используя numpy?

4b9b3361

Ответ 1

Без numpy (ndarray.flatten) можно использовать chain.from_iterable, который является альтернативным конструктором для itertools.chain:

>>> list(chain.from_iterable([[1,2,3],[1,2],[1,4,5,6,7]]))
[1, 2, 3, 1, 2, 1, 4, 5, 6, 7]

Или как еще один подход Pythonic, вы можете использовать понимание списка :

[j for sub in [[1,2,3],[1,2],[1,4,5,6,7]] for j in sub]

Другим функциональным подходом, очень подходящим для коротких списков, может быть также reduce в Python2 и functools.reduce в Python3 (не используйте его для длинных списков):

In [4]: from functools import reduce # Python3

In [5]: reduce(lambda x,y :x+y ,[[1,2,3],[1,2],[1,4,5,6,7]])
Out[5]: [1, 2, 3, 1, 2, 1, 4, 5, 6, 7]

Чтобы сделать его немного быстрее, вы можете использовать встроенный operator.add вместо lambda:

In [6]: from operator import add

In [7]: reduce(add ,[[1,2,3],[1,2],[1,4,5,6,7]])
Out[7]: [1, 2, 3, 1, 2, 1, 4, 5, 6, 7]

In [8]: %timeit reduce(lambda x,y :x+y ,[[1,2,3],[1,2],[1,4,5,6,7]])
789 ns ± 7.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [9]: %timeit reduce(add ,[[1,2,3],[1,2],[1,4,5,6,7]])
635 ns ± 4.38 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

тест:

:~$ python -m timeit "from itertools import chain;chain.from_iterable([[1,2,3],[1,2],[1,4,5,6,7]])"
1000000 loops, best of 3: 1.58 usec per loop
:~$ python -m timeit "reduce(lambda x,y :x+y ,[[1,2,3],[1,2],[1,4,5,6,7]])"
1000000 loops, best of 3: 0.791 usec per loop
:~$ python -m timeit "[j for i in [[1,2,3],[1,2],[1,4,5,6,7]] for j in i]"
1000000 loops, best of 3: 0.784 usec per loop

Тест @Will для ответа, который использовал sum (быстро для короткого списка, но не для длинного):

:~$ python -m timeit "sum([[1,2,3],[4,5,6],[7,8,9]], [])"
1000000 loops, best of 3: 0.575 usec per loop
:~$ python -m timeit "sum([range(100),range(100)], [])"
100000 loops, best of 3: 2.27 usec per loop
:~$ python -m timeit "reduce(lambda x,y :x+y ,[range(100),range(100)])"
100000 loops, best of 3: 2.1 usec per loop

Ответ 2

Для такого списка мой любимый аккуратный маленький трюк - это просто использовать sum;

sum имеет необязательный аргумент: sum(iterable [, start]), поэтому вы можете сделать:

list_of_lists = [[1,2,3], [4,5,6], [7,8,9]]
print sum(list_of_lists, []) # [1,2,3,4,5,6,7,8,9]

это работает, потому что оператор + является оператором конкатенации для списков, и вы сказали ему, что начальное значение [] - пустой список.

но документация для sum рекомендует использовать itertools.chain вместо этого, поскольку это намного яснее.

Ответ 3

Это будет работать в вашем конкретном случае. Рекурсивная функция будет работать лучше всего, если у вас есть несколько уровней вложенных итераций.

def flatten(input):
    new_list = []
    for i in input:
        for j in i:
            new_list.append(j)
    return new_list