파이썬의 목록 목록에서 간단한 목록을 만드는 지름길이 있는지 궁금합니다.
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']
참고