목록 목록에서 일반 목록을 만드는 방법은 무엇입니까? на Stack Overflow

파이썬의 목록 목록에서 간단한 목록을 만드는 지름길이 있는지 궁금합니다.

for루프 에서 그렇게 할 수 있지만 멋진 “한 줄짜리”가 있을까요? 와 함께 시도했지만 reduce()오류가 발생합니다.

암호

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'


답변

목록의 목록을 감안할 때 l,

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

이는 다음을 의미합니다.

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

설명 : +(에 암시 적 사용 포함)을 기반으로하는 바로 가기 는 L 하위 목록이있을 때 sum필수적입니다 O(L**2). 중간 결과 목록이 계속 길어질수록 각 단계에서 새 중간 결과 목록 오브젝트가 할당되며 모든 항목이 이전 중간 결과에서 복사해야합니다 (마지막으로 추가 된 몇 가지 새로운 결과 포함). 따라서 단순성과 실제 일반성을 잃지 않고 I 항목의 L 하위 목록이 각각 있다고 가정하십시오. 첫 번째 I 항목은 L-1 번 앞뒤로 복사되고 두 번째 I 항목은 L-2 번 등으로 복사됩니다. 총 사본 수는 1에서 L까지 제외 된 x에 대한 x의 합계의 1 배 I * (L**2)/2입니다.

목록 이해는 하나의 목록을 한 번만 생성하고 각 항목을 원래 위치에서 결과 목록으로 정확히 한 번 복사합니다.


답변

당신은 사용할 수 있습니다 itertools.chain():

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

또는 연산자로itertools.chain.from_iterable() 목록의 압축을 풀 필요가없는을 사용할 수 있습니다 .*

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

답변

저자의 메모 : 이것은 비효율적입니다. 그러나 monoid 가 굉장 하기 때문에 재미 있습니다. 프로덕션 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].

목록 목록에서만 작동합니다. 목록 목록의 경우 다른 솔루션이 필요합니다.


답변

나는 perfplot (내 애완 동물 프로젝트, 본질적으로 래퍼 timeit) 으로 가장 많이 제안 된 솔루션을 테스트 했으며

functools.reduce(operator.iconcat, a, [])

여러 개의 작은 목록과 몇 개의 긴 목록이 연결되어있을 때 가장 빠른 솔루션입니다. ( operator.iadd똑같이 빠릅니다.)


줄거리를 재현하는 코드 :

import functools
import itertools
import numpy
import operator
import perfplot


def forfor(a):
    return [item for sublist in a for item in sublist]


def sum_brackets(a):
    return sum(a, [])


def functools_reduce(a):
    return functools.reduce(operator.concat, a)


def functools_reduce_iconcat(a):
    return functools.reduce(operator.iconcat, a, [])


def itertools_chain(a):
    return list(itertools.chain.from_iterable(a))


def numpy_flat(a):
    return list(numpy.array(a).flat)


def numpy_concatenate(a):
    return list(numpy.concatenate(a))


perfplot.show(
    setup=lambda n: [list(range(10))] * n,
    # setup=lambda n: [list(range(n))] * 10,
    kernels=[
        forfor,
        sum_brackets,
        functools_reduce,
        functools_reduce_iconcat,
        itertools_chain,
        numpy_flat,
        numpy_concatenate,
    ],
    n_range=[2 ** k for k in range(16)],
    xlabel="num lists (of length 10)",
    # xlabel="len lists (10 lists total)"
)

답변

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]

답변

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))

… 설정 도구 :

>>> from setuptools.namespaces import flatten
>>> list(flatten(l))

답변

다음은 숫자 , 문자열 , 중첩 목록 및 혼합 컨테이너에 적용되는 일반적인 접근 방식입니다 .

암호

#from typing import Iterable 
from collections import Iterable                            # < py38


def flatten(items):
    """Yield items from any nested iterable; see Reference."""
    for x in items:
        if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
            for sub_x in flatten(x):
                yield sub_x
        else:
            yield x

참고 사항 :

  • 파이썬 3에서 yield from flatten(x)대체 할 수 있습니다for sub_x in flatten(x): yield sub_x
  • 파이썬 3.8에서 추상 기본 클래스가 된다 이동 에서 collection.abc받는 typing모듈.

데모

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

mixed = [[1, [2]], (3, 4, {5, 6}, 7), 8, "9"]              # numbers, strs, nested & mixed
list(flatten(mixed))
# [1, 2, 3, 4, 5, 6, 7, 8, '9']

참고

  • 이 솔루션은 Beazley, D. 및 B. Jones 의 레시피에서 수정되었습니다 . 레시피 4.14, Python Cookbook 3rd Ed., O’Reilly Media Inc. Sebastopol, CA : 2013.
  • 이전 SO post , 아마도 원래 데모를 찾았 습니다 .