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


3368

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

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'

20
여기에 대한 자세한 설명이 있습니다 : rightfootin.blogspot.com/2006/09/more-on-python-flatten.html , 임의로 중첩 된 목록 목록을 병합하는 몇 가지 방법을 설명합니다. 재미있는 읽을 거리!
RichieHindle 2016 년

6
다른 답변이 더 좋지만 실패한 이유는 'extend'메서드가 항상 None을 반환하기 때문입니다. 길이가 2 인 목록의 경우 작동하지만 None을 반환합니다. 더 긴 목록의 경우 처음 2 개 인수를 사용하며 None을 반환합니다. 그런 다음 None.extend (<third arg>)로 계속해서이 오류를 일으킨다
13:48에 mehtunguh

@ shawn-chin 솔루션은 여기에서 더 화려하지만 시퀀스 유형을 보존 해야하는 경우 목록 목록이 아닌 튜플이 있다고 가정하면 reduce (operator.concat, tuple_of_tuples)를 사용해야합니다. tuples와 함께 operator.concat을 사용하면 chain.from_iterables보다 list가 더 빠릅니다.
Meitham

답변:


4789

목록의 목록을 감안할 때 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입니다.

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


486
itertools.chain.from_iterable:을 사용하여 동일한 데이터로 테스트를 시도했습니다 $ python -mtimeit -s'from itertools import chain; l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'list(chain.from_iterable(l))'. 여기에 표시된 대안 중 가장 빠른 중첩 목록 이해보다 두 배 이상 빠릅니다.
직관

274
구문을 중첩 된 for 루프처럼 정확하게 생각할 수있을 때까지 구문을 이해하기 어렵다는 것을 알았습니다. l의 하위 목록 : 하위 목록의 항목 : yield item
Rob Crowell

23
@BorisChervenkov : list()반복자를 목록으로 구현하기 위해 호출을 래핑했습니다 .
intuited

163
[나무의 잎을위한 숲의 나무를위한 잎] 이해하고 적용하기가 더 쉬울 수 있습니다.
John Mee

80
@Joel은 실제로 list(itertools.chain.from_iterable(l))다른 의견과 Shawn의 답변에서 알 수 있듯이 실제로 오늘날 최고입니다.
Alex Martelli

1566

당신은 사용할 수 있습니다 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))

13
이것은 목록 이해력보다 덜 직관적 인 *까다로운 것입니다 chain. 체인은 매개 변수로 전달 된 반복 가능 항목 만 결합하고 *는 최상위 레벨 목록을 매개 변수로 확장하므로 chain모든 반복 가능 항목을 결합하지만 더 이상 내려 가지는 않습니다. 이 경우 체인을 사용하는 것보다 이해력을 더 읽기 쉽게 만듭니다.
Tim Dierks

52
@TimDierks : "Python 구문을 이해해야한다"는 것이 Python에서 주어진 기술을 사용하는 것에 대한 논쟁인지 잘 모르겠습니다. 물론 복잡한 사용법은 혼동 될 수 있지만 "스 플래트"연산자는 일반적으로 많은 상황에서 유용하며 특히 모호한 방식으로 사용하지 않습니다. 초보자에게 분명하지 않은 모든 언어 기능을 거부한다는 것은 한 손을 등 뒤로 묶는다는 의미입니다. 당신이 그것을 이해하는 동안 목록 이해력을 버릴 수도 있습니다. 다른 배경을 가진 사용자는 for반복적으로 append더 분명한 루프를 찾을 수 있습니다.
ShadowRanger

이 답변과 다른 답변은 최상위 수준에도 값이 포함되어 있으면 잘못된 결과를 제공합니다. 예를 들어, list = [["abc","bcd"],["cde","def"],"efg"]출력은["abc", "bcd", "cde", "def", "e", "f", "g"].
gouravkr

906

저자의 메모 : 이것은 비효율적입니다. 그러나 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].

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


99
꽤 깔끔하고 영리하지만 읽기가 어렵 기 때문에 사용하지 않을 것입니다.
andrewrk

87
이것은 화가의 알고리즘 인 Shlemiel 입니다.
Mike Graham

44
리스트의 추가 연산은 a를 형성하는데 Monoid, 이는 +일반적인 의미 로 연산 을 생각하기위한 가장 편리한 추상화 중 하나입니다 (숫자에만 국한되지 않음). 따라서이 답변은 목록을 단일체로 (올바르게) 처리 한 경우 +1이 필요합니다. 성능에 관한 것입니다 ...
ulidtko

7
잘 @andrewrk, 어떤 사람들이 그 일의 가장 깨끗한 방법이라고 생각 : youtube.com/watch?v=IOiZatlZtGU 왜 멋진 단지 모든 사람들이이 방법을 수행 할 때까지 몇 년을 기다릴 필요가있다되지 않는 것들 : ) 발견되고 발명되지 않은 프로그래밍 언어 (및 추상화)를 사용합시다. Monoid가 발견되었습니다.
jhegedus

11
이차의 이차적 인 측면으로 인해 이것은 매우 비효율적 인 방법입니다.
장 프랑수아 파브르

459

나는 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)"
)

25
거대한 중첩 목록의 경우 'list (numpy.array (a) .flat)'은 위의 모든 기능 중에서 가장 빠릅니다.
사라

정규식을 사용하여 시도했습니다 : 'list (map (int, re.findall (r "[\ w] +", str (a))))'. numpy_concatenate보다 속도가 약간 느림
Justas

3 차원 perfplot을 수행하는 방법이 있습니까? 평균 배열 크기별 배열 수?
레오

나는 당신의 해결책을 좋아합니다. 짧고 간단하며 효율적 :-)
ShadyMBA

181
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]

19
reduce(operator.add, l)reduce버전 을 수행하는 올바른 방법 입니다. 내장은 람다보다 빠릅니다.
agf

3
@agf 방법은 다음과 같습니다. * timeit.timeit('reduce(operator.add, l)', 'import operator; l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]', number=10000) 0.017956018447875977 * timeit.timeit('reduce(lambda x, y: x+y, l)', 'import operator; l=[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7]]', number=10000) 0.025218963623046875
lukmdo

8
이것은 화가의 알고리즘 Shlemiel joelonsoftware.com/articles/fog0000000319.html
Mike Graham

2
이 경우에만 사용할 수 있습니다 integers. 그러나 목록에 포함되어 있다면 string어떨까요?
프레디

3
@Freddy :이 operator.add함수는 정수 목록과 문자열 목록 모두에서 동일하게 작동합니다.
Greg Hewgill

119

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

4
flatten = itertools.chain.from_iterable정답이어야합니다
geckos

3
좋은 답변입니다! 판다의 경우 l = [[[[1, 2, 3], [4, 5]], 5]에도 적용
Markus Dutschke

1
팬더 솔루션이 마음에 듭니다. 다음과 같은 것이 있으면 list_of_menuitems = [1, 2, [3, [4, 5, [6]]]]결과가됩니다 : [1, 2, 3, 4, 5, 6]. 내가 놓친 것은 평평한 수준입니다.
imjoseangel

115

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

암호

#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 , 아마도 원래 데모를 찾았 습니다 .

5
나는 당신의 해결책을 보지 못했기 때문에 거의 똑같이 썼다 ... 여기서 내가 찾은 것은 "다수의 목록을 재귀 적으로 평평하다"... (+1)
Martin Thoma

3
@MartinThoma 대단히 감사합니다. 참고로 중첩 iterable을 병합하는 것이 일반적인 관행이라면이를 잘 처리하는 타사 패키지가 있습니다. 이것은 바퀴를 재발 명하는 것을 막을 수 있습니다. 나는 more_itertools이 게시물에서 논의 된 다른 사람들 중에서 언급 했습니다. 건배.
pylang

어쩌면 traverse이 방법으로 나무의 좋은 이름 일 수도 있지만 중첩 된 목록을 고수 함으로써이 대답에 보편적 이지 않을 것 입니다.
Wolf

if hasattr(x, '__iter__')가져 오기 / 확인 대신 확인할 수 있으며 Iterable문자열도 제외됩니다.
Ryan Allen

중첩 된 목록 중 하나에 문자열 목록이 있으면 위의 코드가 작동하지 않는 것 같습니다. [1, 2, [3, 4], [4], [], 9, 9.5, 'ssssss', [ 'str', 'sss', 'ss'], [3, 4, 5]] 출력 : -[1, 2, 3, 4, 4, 9, 9.5, 'ssssss', 3, 4, 5]
sunnyX

51

얼마나 깊이 중첩되어 있는지 모르는 데이터 구조를 병합하려는 경우 1을 사용할 수 있습니다.iteration_utilities.deepflatten

>>> from iteration_utilities import deepflatten

>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> list(deepflatten(l, depth=1))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

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

생성기이므로 결과를 캐스트 list하거나 명시 적으로 반복해야합니다.


하나의 레벨 만 평탄화하고 각 항목 자체가 반복 가능한 경우 iteration_utilities.flatten자체를 얇은 래퍼로 사용할 수도 있습니다 itertools.chain.from_iterable.

>>> from iteration_utilities import flatten
>>> l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
>>> list(flatten(l))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

몇 가지 타이밍을 추가하기 만하면됩니다 (이 답변에 제시된 기능을 포함하지 않은 Nico Schlömer 답변을 기반으로 함).

여기에 이미지 설명을 입력하십시오

광범위한 값 범위를 수용하기위한 로그-로그 플롯입니다. 질적 추론 : 낮을수록 좋습니다.

결과는 iterable에 내부 iterables가 몇 개만 포함 된 경우 sum가장 빠르지 만 긴 iterable의 경우 itertools.chain.from_iterable, iteration_utilities.deepflatten또는 중첩 이해력이 itertools.chain.from_iterable가장 빠르며 합리적인 성능을 가지고 있음을 보여줍니다 (Nico Schlömer에서 이미 알 수 있음).

from itertools import chain
from functools import reduce
from collections import Iterable  # or from collections.abc import Iterable
import operator
from iteration_utilities import deepflatten

def nested_list_comprehension(lsts):
    return [item for sublist in lsts for item in sublist]

def itertools_chain_from_iterable(lsts):
    return list(chain.from_iterable(lsts))

def pythons_sum(lsts):
    return sum(lsts, [])

def reduce_add(lsts):
    return reduce(lambda x, y: x + y, lsts)

def pylangs_flatten(lsts):
    return list(flatten(lsts))

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

def reduce_concat(lsts):
    return reduce(operator.concat, lsts)

def iteration_utilities_deepflatten(lsts):
    return list(deepflatten(lsts, depth=1))


from simple_benchmark import benchmark

b = benchmark(
    [nested_list_comprehension, itertools_chain_from_iterable, pythons_sum, reduce_add,
     pylangs_flatten, reduce_concat, iteration_utilities_deepflatten],
    arguments={2**i: [[0]*5]*(2**i) for i in range(1, 13)},
    argument_name='number of inner lists'
)

b.plot()

1 면책 조항 : 나는 그 도서관의 저자입니다


sum임의의 순서에 더 이상 작동하지 않습니다 그것을 시작으로 0하고, functools.reduce(operator.add, sequences)교체 (우리는 그들이 제거 기뻐하지 reduce내장 명령에서?). 유형을 알면 사용하는 것이 더 빠를 수 있습니다 type.__add__.
Yann Vernier

@YannVernier 정보를 주셔서 감사합니다. 파이썬 3.6 에서이 벤치 마크를 실행하고 함께 작동한다고 생각했습니다 sum. 작동이 중단 된 Python 버전을 알고 있습니까?
MSeifert

나는 다소 착각했다. 0는 기본 시작 값이므로 start 인수 를 사용하여 빈 목록으로 시작 하면 작동 하지만 여전히 특수한 경우 문자열이며 join을 사용하도록 지시합니다. foldl대신 구현 중 foldl1입니다. 2.7에서도 같은 문제가 나타납니다.
Yann Vernier

39

진술서를 다시 가져옵니다. 합계는 승자가 아닙니다. 목록이 작을 때 더 빠르지 만. 그러나 목록이 클수록 성능이 크게 저하됩니다.

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

합계 버전이 여전히 1 분 이상 실행 중이며 아직 처리되지 않았습니다!

중간 목록의 경우 :

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

23
정말 작은 목록, 예를 들어 3 개의 하위 목록이있는 목록 일 수도 있습니다.하지만 합의 성능은 O (N ** 2)에 해당하는 반면 목록 이해는 O (N)에 해당하므로 입력 목록을 조금만 늘리면 상황이 반대로됩니다. 실제로 LC는 N이 증가함에 따라 한계보다 "무한하게 빠를 것이다". 나는 파이썬 런타임에서 합계를 디자인하고 첫 번째 구현을 담당했지만 여전히 숫자를 합산하는 것으로 효과적으로 제한하고 사람들에게 제공하는 "매력적인 방해"를 차단하는 방법을 찾았 으면 좋겠다. 목록을 "합계"하려는 사람 ;-).
Alex Martelli 2016 년

38

와 혼동이있는 것 같습니다 operator.add! 두 개의 목록을 함께 추가 할 때 올바른 용어는입니다 concat. operator.concat사용해야합니다.

기능적이라고 생각하면 다음과 같이 쉽습니다. :

>>> from functools import reduce
>>> list2d = ((1, 2, 3), (4, 5, 6), (7,), (8, 9))
>>> reduce(operator.concat, list2d)
(1, 2, 3, 4, 5, 6, 7, 8, 9)

시퀀스 유형이 축소되는 것을 알 수 있으므로 튜플을 공급하면 튜플이 다시 제공됩니다. 목록으로 시도해 봅시다 ::

>>> list2d = [[1, 2, 3],[4, 5, 6], [7], [8, 9]]
>>> reduce(operator.concat, list2d)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

아하, 당신은 목록을 다시 얻는다.

성능은 어떻습니까 ::

>>> list2d = [[1, 2, 3],[4, 5, 6], [7], [8, 9]]
>>> %timeit list(itertools.chain.from_iterable(list2d))
1000000 loops, best of 3: 1.36 µs per loop

from_iterable꽤 빠릅니다! 그러나와 비교하는 것은 아닙니다 concat.

>>> list2d = ((1, 2, 3),(4, 5, 6), (7,), (8, 9))
>>> %timeit reduce(operator.concat, list2d)
1000000 loops, best of 3: 492 ns per loop

1
흠 두 번째 예는 목록도 있어야합니다 (또는 첫 번째 튜플?)
Mr_and_Mrs_D

2
이러한 작은 입력을 사용하는 것은 공정한 비교가 아닙니다. 길이가 1000 인 1000 시퀀스의 경우 0.037 초 동안 list(chain.from_iterable(...))2.5 초를 얻 습니다 reduce(concat, ...). 문제는 reduce(concat, ...)2 차 런타임 을 갖는 반면 chain선형입니다.
kaya3

33

왜 extend를 사용합니까?

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

이것은 잘 작동합니다.


7
for python3from functools import reduce
andorov

죄송합니다 그 대답 정말 느린 참조 나머지의
Mr_and_Mrs_D

이것은 파이썬 2와 3에서 작동하는 가장 이해하기 쉬운 짧은 솔루션입니다. 나는 많은 파이썬 사람들이 처리 할 데이터의 양이 많고 속도에 많은 관심을 갖는 데이터 처리에 있다는 것을 알고 있습니다. 쉘 스크립트를 작성하고 몇 개의 하위 목록에 수십 개의 요소 만 있으면 완벽합니다.
Asfand Qazi

27

more_itertools패키지 설치를 고려하십시오 .

> pip install more_itertools

그것은 flatten( source , itertools recipes ) 의 구현과 함께 제공됩니다 .

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( source , 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]

과연. 이것은 대답이 될 것입니다
brunetton

프로젝트에 패키지를 추가 할 여유가 있다면이 답변이 가장 좋습니다
viddik13

22

함수가 작동하지 않는 이유는 확장 이 배열을 제자리로 확장하고 반환하지 않기 때문입니다. 다음과 같이 람다에서 x를 반환 할 수 있습니다.

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

참고 : 확장은 목록에서 +보다 효율적입니다.


7
extend더로서 사용되는 newlist = [], extend = newlist.extend, for sublist in l: extend(l)는 (약간 큰)을 회피 같이 오버 헤드의 lambda상기 속성에 대한 조회 x, 및 or.
agf

python 3 추가from functools import reduce
Markus Dutschke

17
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]

def flatten(l, a=None): if a is None: a = [][...]
Poik

16

재귀 버전

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]

1
좋아, 수입이 필요하지 않으며 그것이 무엇을하고 있는지 분명합니다 ... 목록을 평탄화, 기간 :)
Goran B.

1
단순히 훌륭합니다!
Sachin Sharma

15

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 배 빠릅니다.

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

14

가변 길이의 텍스트 기반 목록을 처리 할 때 허용되는 답변이 작동하지 않았습니다. 나를 위해 일한 다른 접근법이 있습니다.

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']

13

위의 Anil 함수의 나쁜 특징은 사용자가 항상 수동으로 두 번째 인수를 빈 목록으로 지정해야한다는 것 []입니다. 대신 기본값이어야합니다. 파이썬 객체는 작동하는 방식 때문에 인수가 아닌 함수 내부에 설정해야합니다.

작동하는 기능은 다음과 같습니다.

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]

13

다음은 가장 단순 해 보입니다.

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

차원이 다른 목록에서는 작동하지 않습니다. -1
nurub

10

NumPy의 flat을 사용할 수도 있습니다 .

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

11/02/2016 편집 : 하위 목록의 치수가 동일한 경우에만 작동합니다.


그것이 최적의 솔루션일까요?
RetroCode

6

numpy 사용할 수 있습니다 :
flat_list = list(np.concatenate(list_of_list))


이것은 숫자, 문자열 및 혼합 목록에도 적용됩니다.
Nitin

2
같은 고르지 중첩 된 데이터에 실패[1, 2, [3], [[4]], [5, [6]]]
EL_DON

5

당신이 청소기 모양에 대한 속도의 작은 금액을 포기하고자하는 경우에, 당신은 사용할 수 있습니다 numpy.concatenate().tolist()또는 numpy.concatenate().ravel().tolist():

import numpy

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

%timeit numpy.concatenate(l).ravel().tolist()
1000 loops, best of 3: 313 µs per loop

%timeit numpy.concatenate(l).tolist()
1000 loops, best of 3: 312 µs per loop

%timeit [item for sublist in l for item in sublist]
1000 loops, best of 3: 31.5 µs per loop

문서 numpy.concatenatenumpy.ravel 에서 자세한 내용을 확인할 수 있습니다.


1
같은 고르지 중첩 된 목록이 작동하지 않습니다[1, 2, [3], [[4]], [5, [6]]]
EL_DON

5

내가 찾은 가장 빠른 솔루션 (어쨌든 큰 목록) :

import numpy as np
#turn list into an array and flatten()
np.array(l).flatten()

끝난! 물론 list (l)을 실행하여 목록으로 되돌릴 수 있습니다.


1
이것은 잘못되었습니다. flatten은 nd 배열의 차원을 1로 줄이지 만 목록을 하나로 묶지 않습니다.
Ando Jurai

5

underscore.py패키지 팬을 위한 간단한 코드

from underscore import _
_.flatten([[1, 2, 3], [4, 5, 6], [7], [8, 9]])
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

모든 평탄화 문제를 해결합니다 (목록 항목이 없거나 복잡한 중첩).

from underscore import _
# 1 is none list item
# [2, [3]] is complex nesting
_.flatten([1, [2, [3]], [4, 5, 6], [7], [8, 9]])
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

underscore.py핍으로 설치할 수 있습니다

pip install underscore.py

마찬가지로 pydash 를 사용할 수 있습니다 . 이 버전은 목록 이해력이나 다른 답변보다 훨씬 읽기 쉽습니다.
gliemezis

2
이것은 매우 느립니다.
Nico Schlömer

2
왜 _라는 모듈이 있습니까? 나쁜 이름 인 것 같습니다. 참조 stackoverflow.com/a/5893946/6605826
EL_DON

2
@EL_DON : underscore.py 추가 정보 페이지 "Underscore.py는 우수한 자바 스크립트 라이브러리 underscore.js의 Python 포트입니다." 나는 이것이이 이름의 이유라고 생각합니다. 그리고 네, 그것은 파이썬의 좋은 이름이 아닙니다
Vu Anh

5
def flatten(alist):
    if alist == []:
        return []
    elif type(alist) is not list:
        return [alist]
    else:
        return flatten(alist[0]) + flatten(alist[1:])

질문의 중첩 목록 예에서 [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
python2.7에

@EL_DON은 Python 2.7.5에서 테스트되었습니다. 그것은 잘 작동
englealuze

5

참고 : 아래는 Python 3.3 이상을 사용하기 때문에 적용됩니다 yield_from. six안정적이지만 타사 패키지이기도합니다. 또는을 사용할 수 있습니다 sys.version.


의 경우 obj = [[1, 2,], [3, 4], [5, 6]]목록 이해 및를 포함하여 여기에있는 모든 솔루션이 좋습니다 itertools.chain.from_iterable.

그러나 약간 더 복잡한 경우를 고려하십시오.

>>> obj = [[1, 2, 3], [4, 5], 6, 'abc', [7], [8, [9, 10]]]

여기 몇 가지 문제가 있습니다.

  • 한 요소 6는 스칼라 일뿐입니다. 반복 할 수 없으므로 위의 경로는 여기서 실패합니다.
  • 하나의 요소 ( 'abc') 기술적으로 반복 가능합니다 (모든 요소 str가 있습니다). 그러나 줄 사이를 조금만 읽으면 해당 줄을 단일 요소로 취급하려고합니다.
  • 마지막 요소 [8, [9, 10]]는 그 자체가 중첩 된 iterable입니다. 기본 목록 이해 및 chain.from_iterable"1 레벨 다운"만 추출

다음과 같이이를 해결할 수 있습니다.

>>> from collections import Iterable
>>> from six import string_types

>>> def flatten(obj):
...     for i in obj:
...         if isinstance(i, Iterable) and not isinstance(i, string_types):
...             yield from flatten(i)
...         else:
...             yield i


>>> list(flatten(obj))
[1, 2, 3, 4, 5, 6, 'abc', 7, 8, 9, 10]

여기서, 하위 요소 (1)이 IterableABC from에서 반복 itertools가능한지 확인하고 (2) 요소가 "문자열과 유사 하지 " 않은지 확인하려고합니다 .


1
당신은 여전히 파이썬에서 2 호환성, 변화에 관심이 있다면 yield fromA와 for루프, 예를 들면for x in flatten(i): yield x
pylang

5
flat_list = []
for i in list_of_list:
    flat_list+=i

이 코드는 목록을 끝까지 확장하므로 잘 작동합니다. 그것은 매우 유사하지만 하나의 for 루프 만 있습니다. 따라서 2 개의 for 루프를 추가하는 것보다 덜 복잡합니다.


5
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]]

대부분의 다른 솔루션에서 오류가 발생하지만이 솔루션에서 처리합니다.


질문에 "목록 목록"이 표시되지만 예제 목록에 목록이 아닌 항목이 포함되어 있습니다. 대부분의 다른 솔루션은 원래 질문에 충실합니다. 솔루션은 더 넓은 문제를 해결하지만 먼저 설치해야하는 기본이 아닌 Python 패키지 (nltk)가 필요합니다.
simonobo

4

이것은 가장 효율적인 방법은 아니지만 하나의 라이너 (실제로 두 개의 라이너)를 넣는 것으로 생각했습니다. 두 버전 모두 임의의 계층 구조 중첩 목록에서 작동하며 언어 기능 (Python3.5) 및 재귀를 이용합니다.

def make_list_flat (l):
    flist = []
    flist.extend ([l]) if (type (l) is not list) else [flist.extend (make_list_flat (e)) for e in l]
    return flist

a = [[1, 2], [[[[3, 4, 5], 6]]], 7, [8, [9, [10, 11], 12, [13, 14, [15, [[16, 17], 18]]]]]]
flist = make_list_flat(a)
print (flist)

출력은

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

이것은 깊이 우선 방식으로 작동합니다. 재귀는 목록에없는 요소를 찾을 때까지 내려간 다음 지역 변수를 확장 flist한 다음 부모에게 롤백합니다. flist반환 될 때마다 flist목록 이해에있는 부모로 확장됩니다 . 따라서 루트에서 플랫 목록이 리턴됩니다.

위의 목록은 여러 로컬 목록을 만들어 부모 목록을 확장하는 데 사용되는 목록을 반환합니다. 이 문제를 해결하는 방법 flist은 아래와 같이 gloabl을 만드는 것일 수 있습니다 .

a = [[1, 2], [[[[3, 4, 5], 6]]], 7, [8, [9, [10, 11], 12, [13, 14, [15, [[16, 17], 18]]]]]]
flist = []
def make_list_flat (l):
    flist.extend ([l]) if (type (l) is not list) else [make_list_flat (e) for e in l]

make_list_flat(a)
print (flist)

다시 출력

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

지금은 효율성에 대해 잘 모르겠습니다.


append (l) 대신 extend ([l])를 사용하는 이유는 무엇입니까?
Maciek

3

이종 및 동종 정수 목록에 작동하는 또 다른 특이한 접근 방식 :

from typing import List


def flatten(l: list) -> List[int]:
    """Flatten an arbitrary deep nested list of lists of integers.

    Examples:
        >>> flatten([1, 2, [1, [10]]])
        [1, 2, 1, 10]

    Args:
        l: Union[l, Union[int, List[int]]

    Returns:
        Flatted list of integer
    """
    return [int(i.strip('[ ]')) for i in str(l).split(',')]

그것은 ᴡʜᴀᴄᴋᴀᴍᴀᴅᴏᴏᴅʟᴇ3000이 이미 게시 한 것의 더 복잡하고 조금 느린 방법입니다. 나는 어제 그의 제안을 재발견했다. 그래서이 접근법은 요즘 꽤 인기가있는 것처럼 보인다;)
Darkonaut

wierd_list = [[1, 2, 3], [4, 5, 6], [7], [8, 9], 10]nice_list=[1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 0]
확실

하나의 라이너로 내 코드는 다음과 같습니다. flat_list = [int(e.replace('[','').replace(']','')) for e in str(deep_list).split(',')]
tharndt

1
당신은 실제로 +1입니다. ᴡʜᴀᴄᴋᴀᴍᴀᴅᴏᴏᴅʟᴇ3000의 제안은 여러 자리 숫자에서 작동하지 않습니다. 코드를 단순화하고 작성할 수 [int(e.strip('[ ]')) for e in str(deep_list).split(',')]있습니다. 그러나 실제 사용 사례에 대한 Deleet의 제안을 따르는 것이 좋습니다. 그것은 해키 타입 변환을 포함하지 않으며, 자연스럽게 혼합 타입 목록을 처리하기 때문에 더 빠르고 다목적입니다.
Darkonaut

2
불행하게도. 그러나 나는이 코드를 최근에 보았다 : Python Practice Book 6.1.2
tharndt
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.