programing

비정규(임의로 내포된) 리스트 평탄화

stoneblock 2023. 4. 29. 08:15

비정규(임의로 내포된) 리스트 평탄화

예, 이 주제는 이전에 다룬 적이 있는 것으로 알고 있습니다.

제가로는 한해결책은 만제가한아는, 를제모솔다든루같다실음니패합목은록서와 같은 합니다.[[[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

이게 최선의 방법입니까?제가 뭔가 간과했나요?무슨 문제 있어요?

제너레이터 기능을 사용하면 예제를 더 쉽게 읽고 성능을 향상시킬 수 있습니다.

파이썬 2

2.6에 추가된 ABC 사용:

from collections import Iterable

def flatten(xs):
    for x in xs:
        if isinstance(x, Iterable) and not isinstance(x, basestring):
            for item in flatten(x):
                yield item
        else:
            yield x

파이썬 3

에서 파썬에 3서이는basestring더 이상은 아니지만, 튜플.(str, bytes)동일한 효과를 제공합니다.또한 연산자는 생성기에서 항목을 한 번에 하나씩 반환합니다.

from collections.abc import Iterable

def flatten(xs):
    for x in xs:
        if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
            yield from flatten(x)
        else:
            yield x

내 솔루션:

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]

튜플과 목록을 모두 처리하고 위치 인수를 혼합하여 넣을 수 있는 재귀적 평탄화의 기능적 버전이 여기 있습니다.전체 시퀀스를 순서대로 생성하는 생성기를 arg by 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]

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

의 이버의입니다.flattenpython의 재귀 제한을 피하므로 임의로 심층 중첩 반복 가능한 항목으로 작동합니다.이것은 문자열과 임의의 반복 가능한 것(심지어 무한한 것)을 처리할 수 있는 생성기입니다.

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
def flatten(xs):
    res = []
    def loop(ys):
        for i in ys:
            if isinstance(i, list):
                loop(i)
            else:
                res.append(i)
    loop(xs)
    return res

판다는 이것을 하는 기능이 있습니다.그것은 당신이 언급한 것처럼 반복기를 반환합니다.

In [1]: import pandas
In [2]: pandas.core.common.flatten([[[1, 2, 3], [4, 5]], 6])
Out[2]: <generator object flatten at 0x7f12ade66200>
In [3]: list(pandas.core.common.flatten([[[1, 2, 3], [4, 5]], 6]))
Out[3]: [1, 2, 3, 4, 5, 6]

여기 더 흥미로운 대답이 있습니다...

import re

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

    return(d)

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

타사 패키지에서 사용할 수 있습니다.

>>> from iteration_utilities import deepflatten
>>> L = [[[1, 2, 3], [4, 5]], 6]
>>> list(deepflatten(L))
[1, 2, 3, 4, 5, 6]

>>> list(deepflatten(L, types=list))  # only flatten "inner" lists
[1, 2, 3, 4, 5, 6]

반복기이기 때문에 반복해야 합니다(예: 다음과 같이 포장).list또는 루프에서 사용).내부적으로는 재귀적 접근 방식 대신 반복적 접근 방식을 사용하며 C 확장으로 작성되어 순수 파이썬 접근 방식보다 더 빠를 수 있습니다.

>>> %timeit list(deepflatten(L))
12.6 µs ± 298 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
>>> %timeit list(deepflatten(L, types=list))
8.7 µs ± 139 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

>>> %timeit list(flatten(L))   # Cristian - Python 3.x approach from https://stackoverflow.com/a/2158532/5393381
86.4 µs ± 4.42 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

>>> %timeit list(flatten(L))   # Josh Lee - https://stackoverflow.com/a/2158522/5393381
107 µs ± 2.99 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

>>> %timeit list(genflat(L, list))  # Alex Martelli - https://stackoverflow.com/a/2159079/5393381
23.1 µs ± 710 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

의 저자입니다.iteration_utilities도서관.

Python에서 불규칙한 목록을 평평하게 만들 수 있는 기능을 만드는 것은 재미있었지만, 물론 Python이 (프로그래밍을 재미있게 만들기 위해) 그런 것입니다.다음 생성기는 몇 가지 주의 사항에서 상당히 잘 작동합니다.

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

(예 유그유데수있습다니할지로대형을이예(▁dat▁it).bytearray,bytes,그리고.str개체). 이 반복자에게 , 이는반반복수를할없복사요다는터사니의합실존에유한을 제기한다는 합니다.TypeError.

>>> L = [[[1, 2, 3], [4, 5]], 6]
>>> def flatten(iterable):
    try:
        for item in iterable:
            yield from flatten(item)
    except TypeError:
        yield iterable


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

편집:

저는 이전 시행에 동의하지 않습니다.문제는 반복할 수 없는 것을 평평하게 만들 수 없다는 것입니다.그것은 혼란스럽고 논쟁에 대한 잘못된 인상을 줍니다.

>>> list(flatten(123))
[123]
>>>

다음 생성기는 첫 번째 생성기와 거의 동일하지만 반복할 수 없는 개체를 평평하게 만드는 데 문제가 없습니다.부적절한 인수가 주어졌을 때 예상했던 대로 실패합니다.

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

제너레이터 테스트는 제공된 목록에서 올바르게 작동합니다.하지만, 새로운 코드는 다음을 제기할 것입니다.TypeError반할수없때대주을어졌이상는복때 새로운 .다음은 새 동작의 예입니다.

>>> L = [[[1, 2, 3], [4, 5]], 6]
>>> list(flatten(L))
[1, 2, 3, 4, 5, 6]
>>> list(flatten(123))
Traceback (most recent call last):
  File "<pyshell#32>", line 1, in <module>
    list(flatten(123))
  File "<pyshell#27>", line 2, in flatten
    for item in iterable:
TypeError: 'int' object is not iterable
>>>

여기 임의의 깊이의 목록을 평평하게 만드는 간단한 함수가 있습니다.스택 오버플로를 방지하기 위해 재귀가 없습니다.

from copy import deepcopy

def flatten_list(nested_list):
    """Flatten an arbitrarily nested list, without recursion (to avoid
    stack overflows). Returns a new list, the original list is unchanged.

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

    """
    nested_list = deepcopy(nested_list)

    while nested_list:
        sublist = nested_list.pop(0)

        if isinstance(sublist, list):
            nested_list = sublist + nested_list
        else:
            yield sublist

우아하고 매우 비단결적인 답변이 선택되었지만, 저는 검토를 위해 제 해결책을 제시하겠습니다.

def flat(l):
    ret = []
    for i in l:
        if isinstance(i, list) or isinstance(i, tuple):
            ret.extend(flat(i))
        else:
            ret.append(i)
    return ret

이 코드의 좋고 나쁨을 알려주세요.

이러한 질문에 답하려고 할 때는 해결책으로 제안하는 코드의 한계를 제시해야 합니다.성능에 관한 것이라면 크게 개의치 않겠지만 솔루션으로 제안된 대부분의 코드(승인된 답변 포함)는 깊이가 1000보다 큰 목록을 평평하게 만들지 못합니다.

내가 대부분의 코드를 말할 때 나는 모든 형태의 재귀(또는 재귀적인 표준 라이브러리 함수를 호출)를 사용하는 모든 코드를 의미합니다.모든 재귀 호출에 대해 (호출) 스택이 한 단위씩 증가하고 (기본) 파이썬 호출 스택의 크기가 1000이기 때문에 이 모든 코드는 실패합니다.

통화 스택에 익숙하지 않은 경우 다음과 같은 방법이 도움이 될 수 있습니다(그렇지 않으면 구현으로 스크롤할 수 있습니다).

콜 스택 크기 및 재귀 프로그래밍(비슷한 방식으로 던전)

보물찾기와 출구

여러분이 보물을 찾기 위해 번호가 매겨진 방들이 있는 거대한 지하감옥에 들어간다고 상상해 보세요.당신은 그 장소를 모르지만 보물을 찾는 방법에 대한 몇 가지 표시가 있습니다.각 징후는 수수께끼입니다(어려움은 다양하지만 얼마나 어려울지 예측할 수 없습니다).시간을 절약하기 위한 전략에 대해 조금 생각해 보기로 결정하고 두 가지 관찰을 수행합니다.

  1. 그곳에 가려면 수수께끼를 풀어야 하기 때문에 보물을 찾는 것은 어렵습니다.
  2. 일단 보물이 발견되면 입구로 돌아가는 것은 쉬울지도 모르지만, 다른 방향으로 같은 길을 사용하면 됩니다(비록 이것은 당신의 길을 기억하기 위해 약간의 기억이 필요하지만).

지하감옥에 들어서면 작은 공책이 눈에 띕니다.수수께끼를 푼 후 나가는 모든 방을 적을 때 사용하기로 결정하면(새 방에 들어갈 때), 이렇게 하면 다시 입구로 돌아갈 수 있습니다.그것은 천재적인 생각입니다. 당신은 전략을 실행하는 데 한 푼도 쓰지 않을 것입니다.

던전에 들어가서 처음 1001개의 수수께끼를 성공적으로 풀지만, 계획하지 않은 것이 옵니다. 빌려간 노트북에는 공간이 없습니다.당신은 던전 안에서 영원히 잃어버리는 것보다 보물을 갖지 않는 것을 더 좋아하기 때문에 퀘스트를 포기하기로 결정합니다.

재귀 프로그램 실행

기본적으로, 그것은 보물을 찾는 것과 완전히 같은 것입니다.던전은 컴퓨터의 메모리입니다. 이제 당신의 목표는 보물을 찾는 것이 아니라 어떤 함수를 계산하는 것입니다(주어진 x에 대한 f(x)).표시는 단순히 f(x)를 해결하는 데 도움이 되는 하위 루틴입니다.전략은 콜 스택 전략과 동일하며, 노트북은 스택이고, 객실은 함수의 반환 주소입니다.

x = ["over here", "am", "I"]
y = sorted(x) # You're about to enter a room named `sorted`, note down the current room address here so you can return back: 0x4004f4 (that room address looks weird)
# Seems like you went back from your quest using the return address 0x4004f4
# Let's see what you've collected 
print(' '.join(y))

던전에서 마주친 문제는 여기서도 동일할 것이고, 콜 스택의 크기는 유한합니다(여기서는 1000). 따라서 반환하지 않고 너무 많은 함수를 입력하면 콜 스택을 채우고 다음과 같은 오류가 발생합니다. "탐험가에게, 정말 미안하지만 당신의 노트는 꽉 찼습니다." :RecursionError: maximum recursion depth exceeded호출 스택을 채우기 위해 재귀가 필요하지는 않지만, 비재귀 프로그램이 1000을 호출할 때 다시 호출하지 않고 작동할 가능성은 매우 낮습니다.함수에서 돌아오면 호출 스택이 사용된 주소에서 해방된다는 점도 이해해야 합니다(따라서 함수를 입력하기 전에 반환 주소를 밀어넣고 반환할 때 꺼냅니다). 단함재(순귀))의f번 하면 -- ) " 번호자체출반 - 복다것니 -"를 합니다.f계산이 끝날 때까지 계속해서 (보물이 발견될 때까지) 그리고 돌아올 때까지.f당신이 전화했던 장소로 돌아갈 때까지.f까지 어떤 것입니다.콜 스택은 모든 반환 주소에서 차례로 해방될 때까지 어떤 것에서도 해방되지 않습니다.

이 문제를 방지하는 방법은 무엇입니까?

그것은 사실 꽤 간단합니다: "얼마나 깊이까지 갈 수 있는지 모른다면 재귀를 사용하지 마세요."경우에 따라 Tail Call 재귀가 최적화(TCO)될 수 있는 경우도 있습니다.그러나 파이썬에서는 그렇지 않으며 "잘 작성된" 재귀 함수조차도 스택 사용을 최적화하지 않습니다.이 질문에 대한 Guido의 흥미로운 게시물이 있습니다.꼬리 재귀 제거.

어떤 재귀적인 기능을 반복적으로 만드는 데 사용할 수 있는 기술이 있습니다. 이 기술을 우리는 여러분만의 노트북을 가져오는 것이라고 부를 수 있습니다.예를 들어, 우리의 경우 단순히 목록을 탐색하고 있습니다. 방에 들어가는 것은 하위 목록에 들어가는 것과 같습니다. 스스로에게 물어봐야 할 질문은 목록에서 상위 목록으로 돌아갈 있는 방법입니다.답은 그렇게 복잡하지 않습니다. 다음을 반복합니다.stack비어 있음:

  1. 목록을 .address그리고.index순식간에stack새 하위 목록을 입력할 때 (목록 주소+인덱스도 주소이므로 호출 스택에서 사용하는 것과 동일한 기법을 사용합니다.)
  2. 물건이 발견될 때마다yield (또는목록추가에;추));
  3. 되면, , ▁the를 사용하여 부모 목록으로 .stack 반환(및 ).

목록인 트리의 .A = [1, 2]것들입니다: 간한항목있습다니도단다:.0, 1, 2, 3, 4(의 경우)L = [0, [1,2], 3, 4] 는 다음과 생겼습니다

                    L
                    |
           -------------------
           |     |     |     |
           0   --A--   3     4
               |   |
               1   2

DFS 통과 사전 순서는 L, 0, A, 1, 2, 3, 4입니다. 반복 DFS를 구현하려면 스택도 "필요"합니다.과 같은.stack 리고그고.flat_list):

init.:  stack=[(L, 0)]
**0**:  stack=[(L, 0)],         flat_list=[0]
**A**:  stack=[(L, 1), (A, 0)], flat_list=[0]
**1**:  stack=[(L, 1), (A, 0)], flat_list=[0, 1]
**2**:  stack=[(L, 1), (A, 1)], flat_list=[0, 1, 2]
**3**:  stack=[(L, 2)],         flat_list=[0, 1, 2, 3]
**3**:  stack=[(L, 3)],         flat_list=[0, 1, 2, 3, 4]
return: stack=[],               flat_list=[0, 1, 2, 3, 4]

이 예제에서는 입력 목록(및 트리)에 깊이가 2이므로 스택의 최대 크기는 2입니다.

실행

구현을 위해, 파이썬에서는 간단한 목록 대신 반복기를 사용하여 약간 단순화할 수 있습니다.(하위) 반복기에 대한 참조는 목록 주소와 인덱스를 모두 가지는 대신 하위 목록 반환 주소를 저장하는 데 사용됩니다.이것은 큰 차이는 없지만, 저는 이것이 더 읽기 쉽고 조금 더 빠르다고 생각합니다.

def flatten(iterable):
    return list(items_from(iterable))

def items_from(iterable):
    cursor_stack = [iter(iterable)]
    while cursor_stack:
        sub_iterable = cursor_stack[-1]
        try:
            item = next(sub_iterable)
        except StopIteration:   # post-order
            cursor_stack.pop()
            continue
        if is_list_like(item):  # pre-order
            cursor_stack.append(iter(item))
        elif item is not None:
            yield item          # in-order

def is_list_like(item):
    return isinstance(item, list)

또한 다음과 같은 점에 유의하십시오.is_list_like있습니다isinstance(item, list)더 많은 입력 유형을 처리하도록 변경할 수 있습니다. 여기서는 (가용 가능한) 목록일 뿐인 가장 간단한 버전을 원합니다.그러나 다음과 같은 작업도 수행할 수 있습니다.

def is_list_like(item):
    try:
        iter(item)
        return not isinstance(item, str)  # strings are not lists (hmm...) 
    except TypeError:
        return False

한 항목에 "단순한 항목"으로 간주합니다.flatten_iter([["test", "a"], "b])돌아올 것입니다["test", "a", "b"]그리고 아닌["t", "e", "s", "t", "a", "b"]그런 경우에는iter(item)각 항목에 대해 두 번씩 호출됩니다. 독자가 이것을 더 깨끗하게 만드는 것이 연습이라고 가정해 봅시다.

기타 구현에 대한 테스트 및 비고

리스트는 수 하세요.L용사를 print(L)내부적으로 그것은 재귀적인 호출을 사용할 것이기 때문입니다.__repr__(RecursionError: maximum recursion depth exceeded while getting the repr of an object). 로 )에 대한 , 에 대한 해결책flatten함하는포를 str동일한 오류 메시지와 함께 실패합니다.

솔루션을 테스트해야 하는 경우 다음 기능을 사용하여 간단한 중첩 목록을 생성할 수 있습니다.

def build_deep_list(depth):
    """Returns a list of the form $l_{depth} = [depth-1, l_{depth-1}]$
    with $depth > 1$ and $l_0 = [0]$.
    """
    sub_list = [0]
    for d in range(1, depth):
        sub_list = [d, sub_list]
    return sub_list

이는 다음을 제공합니다.build_deep_list(5)>>>[4, [3, [2, [1, [0]]]]].

저는 간단한 답변을 선호합니다.발전기 없음.재귀 또는 재귀 제한이 없습니다.반복만:

def flatten(TheList):
    listIsNested = True

    while listIsNested:                 #outer loop
        keepChecking = False
        Temp = []

        for element in TheList:         #inner loop
            if isinstance(element,list):
                Temp.extend(element)
                keepChecking = True
            else:
                Temp.append(element)

        listIsNested = keepChecking     #determine if outer loop exits
        TheList = Temp[:]

    return TheList

이 작업은 루프에 대한 내부 루프와 외부 while 루프의 두 개의 목록과 함께 작동합니다.

루프의 내부는 목록을 반복합니다.목록 요소를 찾으면 (1) list.extend()를 사용하여 해당 부분을 한 수준의 중첩으로 평평하게 만들고 (2) Checking을 True로 계속 전환합니다.keep check는 루프 중에 외부를 제어하는 데 사용됩니다.외부 루프가 true로 설정되면 다른 패스에 대해 내부 루프를 트리거합니다.

이러한 패스는 중첩된 목록을 더 이상 찾을 수 없을 때까지 계속 발생합니다.아무 것도 찾을 수 없는 경로가 최종적으로 발생하면 keepChecking은 true로 트립되지 않습니다. 이는 listIsNested가 false로 유지되고 루프가 종료되는 동안 외부가 false로 유지됨을 의미합니다.

그런 다음 플랫 목록이 반환됩니다.

시운전

flatten([1,2,3,4,[100,200,300,[1000,2000,3000]]])

[1, 2, 3, 4, 100, 200, 300, 1000, 2000, 3000]

여기서 이미 사용 가능한 답변을 모두 검토하지는 않았지만, 여기 리스프의 퍼스트 및 휴식 목록 처리 방식을 차용하여 생각해 낸 라이너가 있습니다.

def flatten(l): return flatten(l[0]) + (flatten(l[1:]) if len(l) > 1 else []) if type(l) is list else [l]

여기 단순하고 그리 간단하지 않은 사례가 하나 있습니다.

>>> flatten([1,[2,3],4])
[1, 2, 3, 4]

>>> flatten([1, [2, 3], 4, [5, [6, {'name': 'some_name', 'age':30}, 7]], [8, 9, [10, [11, [12, [13, {'some', 'set'}, 14, [15, 'some_string'], 16], 17, 18], 19], 20], 21, 22, [23, 24], 25], 26, 27, 28, 29, 30])
[1, 2, 3, 4, 5, 6, {'age': 30, 'name': 'some_name'}, 7, 8, 9, 10, 11, 12, 13, set(['set', 'some']), 14, 15, 'some_string', 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
>>> 

이 방법이 반드시 더 빠를지 더 효과적일지는 모르겠지만, 제가 하는 일은 다음과 같습니다.

def flatten(lst):
    return eval('[' + str(lst).replace('[', '').replace(']', '') + ']')

L = [[[1, 2, 3], [4, 5]], 6]
print(flatten(L))

flatten여기서 function은 목록을 문자열로 변환하고 모든 대괄호를 꺼낸 다음 대괄호를 끝에 다시 부착한 다음 목록으로 다시 변환합니다.

, 만약 , 만당신당목신대록, 줄알이에줄묶면았다을로와 줄 [[1, 2], "[3, 4] and [5]"]당신은 다른 것을 해야 할 것입니다.

라이브러리를 사용하면 됩니다.pip install funcy

import funcy


funcy.flatten([[[[1, 1], 1], 2], 3]) # returns generator
funcy.lflatten([[[[1, 1], 1], 2], 3]) # returns list

여기 있습니다.compiler.ast.flatten22.7.5 :

def flatten(seq):
    l = []
    for elt in seq:
        t = type(elt)
        if t is tuple or t is list:
            for elt2 in flatten(elt):
                l.append(elt2)
        else:
            l.append(elt)
    return l

더 나은, 더 빠른 방법이 있습니다(여기에 도달했다면 이미 본 방법).

참고:

버전 2.6부터 사용되지 않음: 컴파일러 패키지가 Python 3에서 제거되었습니다.

아무도 이것을 생각하지 못했다는 것이 놀랍습니다.빌어먹을 재귀 나는 여기 선진국 사람들이 만든 재귀적인 대답을 이해하지 못합니다.어쨌든 여기 제 시도가 있습니다. 주의할 점은 OP의 사용 사례에 매우 구체적이라는 것입니다.

import re

L = [[[1, 2, 3], [4, 5]], 6]
flattened_list = re.sub("[\[\]]", "", str(L)).replace(" ", "").split(",")
new_list = list(map(int, flattened_list))
print(new_list)

출력:

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

저는 이미 많은 멋진 답변들이 있다는 것을 알고 있지만, 저는 문제를 푸는 기능적인 프로그래밍 방법을 사용하는 답변을 추가하고 싶었습니다.이 답변에서 나는 이중 재귀를 사용합니다.

def flatten_list(seq):
    if not seq:
        return []
    elif isinstance(seq[0],list):
        return (flatten_list(seq[0])+flatten_list(seq[1:]))
    else:
        return [seq[0]]+flatten_list(seq[1:])

print(flatten_list([1,2,[3,[4],5],[6,7]]))

출력:

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

재귀 또는 중첩 루프가 없습니다.몇 줄.포맷이 잘 되어 있고 읽기 쉽습니다.

def flatten_deep(arr: list):
    """ Flattens arbitrarily-nested list `arr` into single-dimensional. """

    while arr:
        if isinstance(arr[0], list):  # Checks whether first element is a list
            arr = arr[0] + arr[1:]  # If so, flattens that first element one level
        else:
            yield arr.pop(0)  # Otherwise yield as part of the flat array

flatten_deep(L)

https://github.com/jorgeorpinel/flatten_nested_lists/blob/master/flatten.py 의 내 코드로부터.

이 근처에는 이런 내용이 게시되지 않았고 같은 주제에 대한 비공개 질문을 받고 방금 도착했습니다. 하지만 분할할 목록의 유형을 알고 있다면 다음과 같은 작업을 수행하는 것이 어떻습니까?

>>> a = [1, 2, 3, 5, 10, [1, 25, 11, [1, 0]]]    
>>> g = str(a).replace('[', '').replace(']', '')    
>>> b = [int(x) for x in g.split(',') if x.strip()]

요소의 유형을 알아야 하지만 일반화할 수 있고 속도 면에서도 더 빠를 것 같습니다.

완전히 구식이지만 (데이터 유형에 따라) 작동할 것이라고 생각합니다.

flat_list = ast.literal_eval("[%s]"%re.sub("[\[\]]","",str(the_list)))

여기 또 다른 py2 접근법이 있습니다. 그것이 가장 빠른 것인지 아니면 가장 우아하거나 안전한 것인지 모르겠습니다.

from collections import Iterable
from itertools import imap, repeat, chain


def flat(seqs, ignore=(int, long, float, basestring)):
    return repeat(seqs, 1) if any(imap(isinstance, repeat(seqs), ignore)) or not isinstance(seqs, Iterable) else chain.from_iterable(imap(flat, seqs))

원하는 특정(또는 파생) 유형을 무시할 수 있으며 반복기를 반환하므로 메모리 공간을 줄이기 위해 목록, 튜플, 딕트와 같은 특정 컨테이너로 변환하거나 단순히 사용할 수 있습니다. int...와 같은 초기 반복 불가능한 개체를 처리할 수 있습니다.

대부분의 무거운 리프팅은 C에서 수행됩니다. 왜냐하면 제가 알기로는 그것이 어떻게 구현되는지 알고 있기 때문입니다. 그래서 재귀적이지만, AFAIK는 함수 호출이 C에서 발생하기 때문에 파이썬 재귀 깊이에 의해 제한되지 않습니다. 비록 이것이 당신이 메모리에 의해 제한된다는 것을 의미하지는 않지만,특히 현재 스택 크기에 한계가 있는 OS X(OS X Mavericks)에서는...

조금 더 빠른 접근 방식이 있지만 휴대성이 떨어지는 방법은 입력의 기본 요소를 명시적으로 결정할 수 있다고 가정할 경우에만 사용합니다. 그렇지 않으면 무한 재귀가 발생하고 스택 크기가 제한된 OS X는 분할 오류를 상당히 빠르게 발생시킵니다.

def flat(seqs, ignore={int, long, float, str, unicode}):
    return repeat(seqs, 1) if type(seqs) in ignore or not isinstance(seqs, Iterable) else chain.from_iterable(imap(flat, seqs))

대 수)가를 무시해야 하는 데 O(유형 수)가 . 물론 된 유형을 이지만, 이 바로 이 가 사용하는 입니다. 물론 명시된 무시된 유형의 파생된 값은 실패할 것이지만, 이것이 바로 사용되는 이유입니다.str,unicode그러니 조심해서 사용하세요...

테스트:

import random

def test_flat(test_size=2000):
    def increase_depth(value, depth=1):
        for func in xrange(depth):
            value = repeat(value, 1)
        return value

    def random_sub_chaining(nested_values):
        for values in nested_values:
            yield chain((values,), chain.from_iterable(imap(next, repeat(nested_values, random.randint(1, 10)))))

    expected_values = zip(xrange(test_size), imap(str, xrange(test_size)))
    nested_values = random_sub_chaining((increase_depth(value, depth) for depth, value in enumerate(expected_values)))
    assert not any(imap(cmp, chain.from_iterable(expected_values), flat(chain(((),), nested_values, ((),)))))

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

$ uname -a
Darwin Samys-MacBook-Pro.local 13.3.0 Darwin Kernel Version 13.3.0: Tue Jun  3 21:27:35 PDT 2014; root:xnu-2422.110.17~1/RELEASE_X86_64 x86_64
$ python --version
Python 2.7.5

라이브러리를 사용하지 않는 경우:

def flat(l):
    def _flat(l, r):    
        if type(l) is not list:
            r.append(l)
        else:
            for i in l:
                r = r + flat(i)
        return r
    return _flat(l, [])



# example
test = [[1], [[2]], [3], [['a','b','c'] , [['z','x','y']], ['d','f','g']], 4]    
print flat(test) # prints [1, 2, 3, 'a', 'b', 'c', 'z', 'x', 'y', 'd', 'f', 'g', 4]

용사를 합니다.itertools.chain:

import itertools
from collections import Iterable

def list_flatten(lst):
    flat_lst = []
    for item in itertools.chain(lst):
        if isinstance(item, Iterable):
            item = list_flatten(item)
            flat_lst.extend(item)
        else:
            flat_lst.append(item)
    return flat_lst

또는 체인 없이:

def flatten(q, final):
    if not q:
        return
    if isinstance(q, list):
        if not isinstance(q[0], list):
            final.append(q[0])
        else:
            flatten(q[0], final)
        flatten(q[1:], final)
    else:
        final.append(q)

임의깊이로 중첩된 목록을 해결하기 위해 재귀적인 방법을 사용했습니다.

def combine_nlist(nlist,init=0,combiner=lambda x,y: x+y):
    '''
    apply function: combiner to a nested list element by element(treated as flatten list)
    '''
    current_value=init
    for each_item in nlist:
        if isinstance(each_item,list):
            current_value =combine_nlist(each_item,current_value,combiner)
        else:
            current_value = combiner(current_value,each_item)
    return current_value

따라서 function combine_nlist를 정의한 후에는 이 함수 do flating을 쉽게 사용할 수 있습니다.또는 하나의 기능으로 결합할 수 있습니다.어떤 중첩된 목록에도 적용할 수 있기 때문에 제 솔루션이 좋습니다.

def flatten_nlist(nlist):
    return combine_nlist(nlist,[],lambda x,y:x+[y])

결과

In [379]: flatten_nlist([1,2,3,[4,5],[6],[[[7],8],9],10])
Out[379]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

가장 쉬운 방법은 다음을 사용하여 morph 라이브러리를 사용하는 것입니다.pip install morph.

코드는 다음과 같습니다.

import morph

list = [[[1, 2, 3], [4, 5]], 6]
flattened_list = morph.flatten(list)  # returns [1, 2, 3, 4, 5, 6]

이것은 python2의 간단한 플랫 구현입니다.

flatten=lambda l: reduce(lambda x,y:x+y,map(flatten,l),[]) if isinstance(l,list) else [l]

test=[[1,2,3,[3,4,5],[6,7,[8,9,[10,[11,[12,13,14]]]]]],]
print flatten(test)

#output [1, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

언급URL : https://stackoverflow.com/questions/2158395/flatten-an-irregular-arbitrarily-nested-list-of-lists