[python] 불규칙한 목록 목록을 병합

그렇습니다.이 주제는 이전 ( 여기 , 여기 , 여기 , 여기 )에서 다루었 음을 알고 있지만, 아는 한 하나를 제외한 모든 솔루션은 다음과 같은 목록에서 실패합니다.

L = [[[1, 2, 3], [4, 5]], 6]

원하는 출력이있는 곳

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

또는 아마도 더 나은 반복자입니다. 임의의 중첩에서 작동하는 유일한 해결책 은이 질문에서 찾을 수 있습니다 .

def flatten(x):
    result = []
    for el in x:
        if hasattr(el, "__iter__") and not isinstance(el, basestring):
            result.extend(flatten(el))
        else:
            result.append(el)
    return result

flatten(L)

이것이 최고의 모델입니까? 내가 뭔가 간과 했습니까? 문제가 있습니까?



답변

생성기 함수를 사용하면 예제를 좀 더 쉽게 읽고 성능을 향상시킬 수 있습니다.

파이썬 2

def flatten(l):
    for el in l:
        if isinstance(el, collections.Iterable) and not isinstance(el, basestring):
            for sub in flatten(el):
                yield sub
        else:
            yield el

2.6에 추가 된 Iterable ABC를 사용했습니다 .

파이썬 3

파이썬 3에서는 basestring더 이상 없다, 그러나 당신의 튜플을 사용 str하고 bytes이 같은 효과를 얻을 수 있습니다.

yield from연산자는 한 번에 발전기 하나에서 항목을 반환합니다. 하위 생성기에 위임하기위한구문 은 3.3에서 추가되었습니다.

def flatten(l):
    for el in l:
        if isinstance(el, collections.Iterable) and not isinstance(el, (str, bytes)):
            yield from flatten(el)
        else:
            yield el


답변

내 해결책 :

import collections


def flatten(x):
    if isinstance(x, collections.Iterable):
        return [a for i in x for a in flatten(i)]
    else:
        return [x]

조금 더 간결하지만 거의 동일합니다.


답변

재귀 및 덕 입력을 사용하는 생성기 (Python 3 용으로 업데이트 됨) :

def flatten(L):
    for item in L:
        try:
            yield from flatten(item)
        except TypeError:
            yield item

list(flatten([[[1, 2, 3], [4, 5]], 6]))
>>>[1, 2, 3, 4, 5, 6]


답변

@Andrew의 요청에 따라 @unutbu의 비 재귀 솔루션의 생성기 버전은 다음과 같습니다.

def genflat(l, ltypes=collections.Sequence):
    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]
        yield l[i]
        i += 1

이 발전기의 약간 단순화 된 버전 :

def genflat(l, ltypes=collections.Sequence):
    l = list(l)
    while l:
        while l and isinstance(l[0], ltypes):
            l[0:1] = l[0]
        if l: yield l.pop(0)


답변

다음은 튜플과 목록을 모두 처리하고 위치 인수를 혼합하여 사용할 수있는 재귀 평면화의 기능 버전입니다. arg를 기준으로 arg 전체 순서를 생성하는 생성기를 반환합니다.

flatten = lambda *n: (e for a in n
    for e in (flatten(*a) if isinstance(a, (tuple, list)) else (a,)))

용법:

l1 = ['a', ['b', ('c', 'd')]]
l2 = [0, 1, (2, 3), [[4, 5, (6, 7, (8,), [9]), 10]], (11,)]
print list(flatten(l1, -2, -1, l2))
['a', 'b', 'c', 'd', -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]


답변

이 버전 flatten은 파이썬의 재귀 제한 을 피합니다 (따라서 임의로 깊고 중첩 된 반복 가능 항목과 함께 작동). 문자열과 임의의 이터 러블 (무한대까지도)을 처리 할 수있는 생성기입니다.

import itertools as IT
import collections

def flatten(iterable, ltypes=collections.Iterable):
    remainder = iter(iterable)
    while True:
        first = next(remainder)
        if isinstance(first, ltypes) and not isinstance(first, (str, bytes)):
            remainder = IT.chain(first, remainder)
        else:
            yield first

다음은 그 사용법을 보여주는 몇 가지 예입니다.

print(list(IT.islice(flatten(IT.repeat(1)),10)))
# [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

print(list(IT.islice(flatten(IT.chain(IT.repeat(2,3),
                                       {10,20,30},
                                       'foo bar'.split(),
                                       IT.repeat(1),)),10)))
# [2, 2, 2, 10, 20, 30, 'foo', 'bar', 1, 1]

print(list(flatten([[1,2,[3,4]]])))
# [1, 2, 3, 4]

seq = ([[chr(i),chr(i-32)] for i in range(ord('a'), ord('z')+1)] + list(range(0,9)))
print(list(flatten(seq)))
# ['a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 'e', 'E', 'f', 'F', 'g', 'G', 'h', 'H',
# 'i', 'I', 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N', 'o', 'O', 'p', 'P',
# 'q', 'Q', 'r', 'R', 's', 'S', 't', 'T', 'u', 'U', 'v', 'V', 'w', 'W', 'x', 'X',
# 'y', 'Y', 'z', 'Z', 0, 1, 2, 3, 4, 5, 6, 7, 8]

flatten무한 생성기를 처리 할 수 있지만 무한 중첩을 처리 할 수는 없습니다.

def infinitely_nested():
    while True:
        yield IT.chain(infinitely_nested(), IT.repeat(1))

print(list(IT.islice(flatten(infinitely_nested()), 10)))
# hangs


답변

더 흥미로운 또 다른 대답은 다음과 같습니다.

import re

def Flatten(TheList):
    a = str(TheList)
    b,crap = re.subn(r'[\[,\]]', ' ', a)
    c = b.split()
    d = [int(x) for x in c]

    return(d)

기본적으로 중첩 목록을 문자열로 변환하고 정규 표현식을 사용하여 중첩 구문을 제거한 다음 결과를 (평평한) 목록으로 다시 변환합니다.