etc./StackOverFlow

목록 목록에서 평면 목록을 만드는 방법

청렴결백한 만능 재주꾼 2021. 9. 28. 00:12
반응형

질문자 :Emma


Python의 목록 목록에서 간단한 목록을 만드는 바로 가기가 있습니까?

for 루프에서 할 수 있지만 멋진 "한 줄짜리"가 있습니까?

functools.reduce() 그것을 시도했습니다.

 from functools import 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'


답변자 : Alex Martelli


주어진 목록 t ,

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

이는 다음을 의미합니다.

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

지금까지 게시된 바로 가기보다 빠릅니다. ( t 는 병합할 목록입니다.)

다음은 해당 기능입니다.

 def flatten(t): return [item for sublist in t for item in sublist]

증거로 표준 라이브러리에서 timeit 모듈을 사용할 수 있습니다.

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

설명: + sum 의 묵시적 사용 포함 O(T**2) . 중간 결과 목록이 계속 길어지고 각 단계마다 새로운 중간 결과가 나타납니다. list 개체가 할당되고 이전 중간 결과의 모든 항목이 복사되어야 합니다(마지막에 몇 가지 새 항목이 추가됨). 따라서 단순함을 위해 실제 일반성을 잃지 않고 각각 k 항목의 T 하위 목록이 있다고 가정합니다. 첫 번째 k 항목은 T-1번 앞뒤로 복사되고 두 번째 k 항목은 T-2번 등으로 복사됩니다. 총 사본 수는 k 곱하기 1에서 T까지 x에 대한 x의 합은 제외됩니다. 즉, k * (T**2)/2 입니다.

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



답변자 : Shawn Chin


itertools.chain() 사용할 수 있습니다.

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

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

 merged = list(itertools.chain.from_iterable(list2d))


답변자 : Triptych


작성자의 참고 사항 : 이것은 비효율적입니다. 하지만 재미있습니다. 모노이드가 굉장하기 때문입니다. 프로덕션 Python 코드에는 적합하지 않습니다.

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

이것은 단지 첫 번째 인수에 전달된 iterable의 요소를 합산하고 두 번째 인수를 합계의 초기 값으로 처리합니다(제공되지 않은 경우 0 이 대신 사용되며 이 경우 오류가 발생합니다).

중첩 목록을 합산하기 때문에 실제로 sum([[1,3],[2,4]],[]) 의 결과로 [1,3]+[2,4] 를 얻습니다. 이는 [1,3,2,4] .

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



답변자 : Nico Schlömer


나는 perfplot (내 애완 동물 프로젝트, 본질적으로 timeit 주위의 래퍼)로 가장 제안된 솔루션을 테스트했으며 다음을 찾았습니다.

 import functools import operator 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)" )


답변자 : Greg Hewgill


>>> from functools import reduce >>> 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() 메서드는 유용한 값( functools.reduce() 예상하는) x 를 수정합니다.

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]


답변자 : pylang


다음은 숫자 , 문자열 , 중첩 목록 및 혼합 컨테이너에 적용되는 일반적인 접근 방식입니다. 이렇게 하면 단순 컨테이너와 복잡한 컨테이너를 모두 병합할 수 있습니다( 데모 참조).

암호

 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

참고 :

데모

 simple = [[1, 2, 3], [4, 5, 6], [7], [8, 9]] list(flatten(simple)) # [1, 2, 3, 4, 5, 6, 7, 8, 9] complicated = [[1, [2]], (3, 4, {5, 6}, 7), 8, "9"] # numbers, strs, nested & mixed list(flatten(complicated)) # [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 게시물 , 아마도 원래 데모를 찾았습니다.


답변자 : MSeifert


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

 >>> 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 으로 캐스팅하거나 명시적으로 반복해야 합니다.


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

 >>> 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에 내부 iterable이 몇 개만 포함되어 있으면 sum 이 가장 빠르지만 긴 iterable의 경우 itertools.chain.from_iterable , iteration_utilities.deepflatten 또는 nested comprehension만이 itertools.chain.from_iterable이 가장 빠른 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 면책 조항: 저는 해당 라이브러리의 저자입니다.



답변자 : pylang


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

 > pip install more_itertools

flatten ( itertools 레시피의 source ) 구현과 함께 제공됩니다.

 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]

참고: 문서 에서 언급했듯이 flatten 에는 목록 목록이 필요합니다. 더 불규칙한 입력을 병합하는 방법은 아래를 참조하세요.


버전 2.4부터 more_itertools.collapse( source , abarnet 제공)를 사용하여 더 복잡하고 중첩된 more_itertools.collapse

 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]


답변자 : Igor Krivokon


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

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

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



답변자 : devil in the detail


다음은 나에게 가장 간단한 것 같습니다.

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


답변자 : EL_DON


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]

이것은 underscore._.flatten보다 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


답변자 : mdh


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

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

하위 목록의 차원이 동일한 경우에만 작동합니다.



답변자 : kederrac


list extend 방법을 사용할 수 있습니다. 가장 빠른 것으로 표시됩니다.

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

성능:

 import functools import itertools import numpy import operator import perfplot 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 extend(a): n = [] list(map(n.extend, a)) return n perfplot.show( setup=lambda n: [list(range(10))] * n, kernels=[ functools_reduce_iconcat, extend,itertools_chain, numpy_flat ], n_range=[2**k for k in range(16)], xlabel='num lists', )

산출: 여기에 이미지 설명 입력



답변자 : mkultra


더 깔끔한 모양을 위해 약간의 속도를 포기하려는 경우 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 문서에서 확인할 수 있습니다.



답변자 : englealuze


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


답변자 : Brad Solomon


참고 yield_from 을 사용하기 때문에 Python 3.3 이상에 적용됩니다. 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]] 은 자체적으로 중첩된 이터러블입니다. 기본 목록 이해 및 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)와 반복자를인지 확인 Iterable ,에서 ABC itertools , 그러나 또한 (2) 요소를 확인하고 싶은 것은 "문자열처럼."아닙니다



답변자 : phoxis


이것은 가장 효율적인 방법은 아니지만 한 줄(실제로는 두 줄)을 넣어야 한다고 생각했습니다. 두 버전 모두 임의의 계층 중첩 목록에서 작동하며 언어 기능(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 가 반환될 때마다 list comprehension에서 flist 따라서 루트에서 플랫 목록이 반환됩니다.

위의 것은 여러 로컬 목록을 만들고 부모 목록을 확장하는 데 사용되는 반환합니다. 이에 대한 방법은 아래와 같이 flist 만드는 것일 수 있다고 생각합니다.

 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]

현재로서는 효율성에 대해 확신할 수 없지만.



답변자 : mmj


아래와 같이 동일한 재귀 추가 체계를 사용하는 몇 가지 답변이 있지만 아무도 try 를 사용하지 않아 솔루션을 더 강력하고 Pythonic하게 만듭니다.

 def flatten(itr): for x in itr: try: yield from flatten(x) except TypeError: yield x

사용법 list() 또는 tuple() 과 같은 반복 가능한 빌더에 묶 for 루프에서 사용하려고 합니다.

이 솔루션의 장점은 다음과 같습니다.

  • 모든 종류의 iterable과 작동합니다(미래의 것까지!).
  • 중첩의 모든 조합 및 깊이와 함께 작동
  • 최상위 수준에 베어 항목이 포함된 경우에도 작동합니다.
  • 종속성 없음
  • 효율적(필요하지 않은 나머지 부분에 시간을 낭비하지 않고 중첩된 반복 가능 항목을 부분적으로 병합할 수 있음)
  • 다재다능함(선택하거나 루프에서 이터러블을 빌드하는 데 사용할 수 있음)

NB 모든 반복 가능 항목이 병합되므로 문자열은 단일 문자 시퀀스로 분해됩니다. 이러한 동작이 마음에 들지 않거나 원하지 않는 경우 문자열 및 바이트와 같은 반복 가능한 평면화에서 필터링하는 다음 버전을 사용할 수 있습니다.

 def flatten(itr): if type(itr) in (str,bytes): yield itr else: for x in itr: try: yield from flatten(x) except TypeError: yield x


답변자 : tharndt


이종 및 동종 정수 목록에 대해 작동하는 또 다른 특이한 접근 방식은 다음과 같습니다.

 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(',')]


답변자 : Mehmet Burak Sayıcı


np.hstack(listoflist).tolist()


출처 : Here


출처 : http:www.stackoverflow.com/questions/952914/how-to-make-a-flat-list-out-of-a-list-of-lists">

반응형