Programing

파이썬에서 목록의 목록에 가입

lottogame 2020. 3. 22. 10:39
반응형

파이썬에서 목록의 목록에 가입


이 질문에는 이미 답변이 있습니다.

파이썬에서 목록 목록을 단일 목록 (또는 반복자)에 결합하는 짧은 구문입니까?

예를 들어 다음과 같은 목록이 있으며 a, b 및 c를 반복하고 싶습니다.

x = [["a","b"], ["c"]]

내가 할 수있는 최선은 다음과 같습니다.

result = []
[ result.extend(el) for el in x] 

for el in result:
  print el

import itertools
a = [['a','b'], ['c']]
print(list(itertools.chain.from_iterable(a)))

한 단계 만 깊이 들어가면 중첩 된 이해도 작동합니다.

>>> x = [["a","b"], ["c"]]
>>> [inner
...     for outer in x
...         for inner in outer]
['a', 'b', 'c']

한 줄에, 그것은 다음과 같습니다.

>>> [j for i in x for j in i]
['a', 'b', 'c']

x = [["a","b"], ["c"]]

result = sum(x, [])

이를 평탄화 (flattening)라고하며 많은 구현이 있습니다.

1 수준의 딥 네 스팅에만 작동하지만 어떻습니까?

>>> x = [["a","b"], ["c"]]
>>> for el in sum(x, []):
...     print el
...
a
b
c

이러한 링크에서 가장 완벽한 고속 우아한 구현은 다음과 같습니다.

def flatten(l, ltypes=(list, tuple)):
    ltype = type(l)
    l = list(l)
    i = 0
    while i < len(l):
        while isinstance(l[i], ltypes):
            if not l[i]:
                l.pop(i)
                i -= 1
                break
            else:
                l[i:i + 1] = l[i]
        i += 1
    return ltype(l)

l = []
map(l.extend, list_of_lists)

최단!


이것은 무한히 중첩 된 요소에 대해 재귀 적으로 작동합니다.

def iterFlatten(root):
    if isinstance(root, (list, tuple)):
        for element in root:
            for e in iterFlatten(element):
                yield e
    else:
        yield root

결과:

>>> b = [[ "a", ( "b", "c")], "d"]
>>> 목록 (iterFlatten (b))
[ 'a', 'b', 'c', 'd']

성능 비교 :

import itertools
import timeit
big_list = [[0]*1000 for i in range(1000)]
timeit.repeat(lambda: list(itertools.chain.from_iterable(big_list)), number=100)
timeit.repeat(lambda: list(itertools.chain(*big_list)), number=100)
timeit.repeat(lambda: (lambda b: map(b.extend, big_list))([]), number=100)
timeit.repeat(lambda: [el for list_ in big_list for el in list_], number=100)
[100*x for x in timeit.repeat(lambda: sum(big_list, []), number=1)]

생산 :

>>> import itertools
>>> import timeit
>>> big_list = [[0]*1000 for i in range(1000)]
>>> timeit.repeat(lambda: list(itertools.chain.from_iterable(big_list)), number=100)
[3.016212113769325, 3.0148865239060227, 3.0126415732791028]
>>> timeit.repeat(lambda: list(itertools.chain(*big_list)), number=100)
[3.019953987082083, 3.528754223385439, 3.02181439266457]
>>> timeit.repeat(lambda: (lambda b: map(b.extend, big_list))([]), number=100)
[1.812084445152557, 1.7702404451095965, 1.7722977998725362]
>>> timeit.repeat(lambda: [el for list_ in big_list for el in list_], number=100)
[5.409658160700605, 5.477502077679354, 5.444318360412744]
>>> [100*x for x in timeit.repeat(lambda: sum(big_list, []), number=1)]
[399.27587954973444, 400.9240571138051, 403.7521153804846]

이것은 Windows XP 32 비트의 Python 2.7.1에서 사용되지만 위의 주석에서 @temoto는 from_iterable보다 빠릅니다 map+extend. 따라서 플랫폼과 입력에 따라 다릅니다.

멀리 떨어져 sum(big_list, [])


파티에 늦었지만 ...

나는 파이썬을 처음 사용하고 lisp 배경에서 왔습니다. 이것은 내가 생각해 낸 것입니다 (lulz의 var 이름을 확인하십시오).

def flatten(lst):
    if lst:
        car,*cdr=lst
        if isinstance(car,(list,tuple)):
            if cdr: return flatten(car) + flatten(cdr)
            return flatten(car)
        if cdr: return [car] + flatten(cdr)
        return [car]

작동하는 것 같습니다. 테스트:

flatten((1,2,3,(4,5,6,(7,8,(((1,2)))))))

보고:

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

생성기가 아닌 목록이 필요한 경우 list():

from itertools import chain
x = [["a","b"], ["c"]]
y = list(chain(*x))

당신이 묘사하는 것은 목록 평탄화 하는 것으로 알려져 있으며 ,이 새로운 지식으로 당신은 구글에서 이것에 대한 많은 해결책을 찾을 수 있습니다 (내장 평탄화 방법은 없습니다). http://www.daniel-lemire.com/blog/archives/2006/05/10/flattening-lists-in-python/ 에서 다음 중 하나입니다 .

def flatten(x):
    flat = True
    ans = []
    for i in x:
        if ( i.__class__ is list):
            ans = flatten(i)
        else:
            ans.append(i)
    return ans

항상 감소합니다 (functools에서 더 이상 사용되지 않음).

>>> x = [ [ 'a', 'b'], ['c'] ]
>>> for el in reduce(lambda a,b: a+b, x, []):
...  print el
...
__main__:1: DeprecationWarning: reduce() not supported in 3.x; use functools.reduce()
a
b
c
>>> import functools
>>> for el in functools.reduce(lambda a,b: a+b, x, []):
...   print el
...
a
b
c
>>>

불행히도 목록 연결을위한 더하기 연산자는 함수로 사용할 수 없습니다. 또는 가시성을 향상시키기 위해 람다를 못 생겼 으면 좋을 것입니다.


또는 재귀 작업 :

def flatten(input):
    ret = []
    if not isinstance(input, (list, tuple)):
        return [input]
    for i in input:
        if isinstance(i, (list, tuple)):
            ret.extend(flatten(i))
        else:
            ret.append(i)
    return ret

안타깝게도 파이썬에는 목록을 평평하게하는 간단한 방법이 없습니다. 이 시도:

def flatten(some_list):
    for element in some_list:
        if type(element) in (tuple, list):
            for item in flatten(element):
                yield item
        else:
            yield element

목록을 재귀 적으로 평평하게 만듭니다. 그런 다음 할 수 있습니다

result = []
[ result.extend(el) for el in x] 

for el in flatten(result):
      print el

배열의 요소와 개수를 포함하는 사전을 만들어야 할 때 비슷한 문제가 발생했습니다. 대답은 관련이 있습니다. 목록의 목록을 평평하게하고 필요한 요소를 얻은 다음 그룹과 계산을 수행하기 때문입니다. 파이썬의 map 함수를 사용하여 요소의 튜플을 생성했으며 배열에 대한 수와 그룹별로입니다. groupby는 배열 요소 자체를 키 기능으로 사용합니다. 비교적 새로운 Python 코더로서, 나는 Pythonic 인 동안 이해하기가 더 쉽다는 것을 알게되었습니다.

코드를 논의하기 전에 먼저 평평 해야하는 데이터 샘플이 있습니다.

{ "_id" : ObjectId("4fe3a90783157d765d000011"), "status" : [ "opencalais" ],
  "content_length" : 688, "open_calais_extract" : { "entities" : [
  {"type" :"Person","name" : "Iman Samdura","rel_score" : 0.223 }, 
  {"type" : "Company",  "name" : "Associated Press",    "rel_score" : 0.321 },          
  {"type" : "Country",  "name" : "Indonesia",   "rel_score" : 0.321 }, ... ]},
  "title" : "Indonesia Police Arrest Bali Bomb Planner", "time" : "06:42  ET",         
  "filename" : "021121bn.01", "month" : "November", "utctime" : 1037836800,
  "date" : "November 21, 2002", "news_type" : "bn", "day" : "21" }

Mongo의 쿼리 결과입니다. 아래 코드는 이러한 목록 모음을 평평하게합니다.

def flatten_list(items):
  return sorted([entity['name'] for entity in [entities for sublist in  
   [item['open_calais_extract']['entities'] for item in items] 
   for entities in sublist])

먼저 모든 "엔티티"컬렉션을 추출한 다음 각 엔터티 컬렉션에 대해 사전을 반복하고 name 특성을 추출합니다.


1 단계 평탄화의 경우 속도에 신경 쓰면 시도한 모든 조건에서 이전 답변보다 빠릅니다. (즉, 결과를 목록으로 필요로하는 경우 즉시 결과를 반복해야하는 경우 체인 예제가 더 좋습니다.) 최종 크기 목록을 미리 할당하고 부분을 복사하여 작동합니다. 슬라이스 별 (이터레이터 메소드보다 하위 레벨 블록 사본) :

def join(a):
    """Joins a sequence of sequences into a single sequence.  (One-level flattening.)
    E.g., join([(1,2,3), [4, 5], [6, (7, 8, 9), 10]]) = [1,2,3,4,5,6,(7,8,9),10]
    This is very efficient, especially when the subsequences are long.
    """
    n = sum([len(b) for b in a])
    l = [None]*n
    i = 0
    for b in a:
        j = i+len(b)
        l[i:j] = b
        i = j
    return l

주석이있는 정렬 된 시간 목록 :

[(0.5391559600830078, 'flatten4b'), # join() above. 
(0.5400412082672119, 'flatten4c'), # Same, with sum(len(b) for b in a) 
(0.5419249534606934, 'flatten4a'), # Similar, using zip() 
(0.7351131439208984, 'flatten1b'), # list(itertools.chain.from_iterable(a)) 
(0.7472689151763916, 'flatten1'), # list(itertools.chain(*a)) 
(1.5468521118164062, 'flatten3'), # [i for j in a for i in j] 
(26.696547985076904, 'flatten2')] # sum(a, [])

참고 URL : https://stackoverflow.com/questions/716477/join-list-of-lists-in-python


반응형