[python] 조옮김 / 압축 해제 기능 (zip의 역)?

2 개의 항목 튜플 목록이 있고 첫 번째 항목은 각 튜플의 첫 번째 항목을 포함하고 두 번째 목록은 두 번째 항목을 포함하는 2 개의 목록으로 변환하고 싶습니다.

예를 들면 다음과 같습니다.

original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
# and I want to become...
result = (['a', 'b', 'c', 'd'], [1, 2, 3, 4])

그렇게하는 내장 함수가 있습니까?



답변

zip그 자신의 역이다! 특수 * 연산자를 사용했다면

>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)])
[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]

이것이 작동하는 방식 zip은 인수를 사용하여 호출하는 것 입니다.

zip(('a', 1), ('b', 2), ('c', 3), ('d', 4))

… 인수가 zip직접 튜플로 변환 된 후 전달 되므로 인수가 너무 커질 염려가 없습니다.


답변

당신은 또한 할 수 있습니다

result = ([ a for a,b in original ], [ b for a,b in original ])

그것은 해야 더 확장 할 수 있습니다. 특히 파이썬이 필요하지 않으면 목록 이해력을 확장하지 않는 것이 좋습니다.

(우연히, 튜플 목록이 아닌 2 튜플 (쌍) 목록을 zip만듭니다.)

실제 목록 대신 생성기가 괜찮다면 다음과 같이하십시오.

result = (( a for a,b in original ), ( b for a,b in original ))

생성기는 각 요소를 요청할 때까지 목록을 검색하지 않지만 원래 목록을 계속 참조합니다.


답변

길이가 다른 목록이있는 경우 Patricks 답변에 따라 zip을 사용하지 않을 수 있습니다. 이것은 작동합니다 :

>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)])
[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]

그러나 길이 목록이 다른 경우 zip은 각 항목을 가장 짧은 목록의 길이로 자릅니다.

>>> zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', )])
[('a', 'b', 'c', 'd', 'e')]

아무 함수없이 map을 사용하여 빈 결과를 None으로 채울 수 있습니다.

>>> map(None, *[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', )])
[('a', 'b', 'c', 'd', 'e'), (1, 2, 3, 4, None)]

zip ()은 약간 빠릅니다.


답변

나는 zip(*iterable)내 프로그램에서 (당신이 찾고있는 코드 조각)을 다음 과 같이 사용 하고 싶다.

def unzip(iterable):
    return zip(*iterable)

내가 찾아 unzip더 읽기.


답변

>>> original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
>>> tuple([list(tup) for tup in zip(*original)])
(['a', 'b', 'c', 'd'], [1, 2, 3, 4])

질문에서와 같이 목록의 튜플을 제공합니다.

list1, list2 = [list(tup) for tup in zip(*original)]

두 목록의 압축을 풉니 다.


답변

순진한 접근

def transpose_finite_iterable(iterable):
    return zip(*iterable)  # `itertools.izip` for Python 2 users

다음과 같이 설명 할 수있는 (잠재적으로 무한한) 반복 가능한 유한 반복 가능한 (예 : list/ tuple/ str) 시퀀스에 대해 잘 작동합니다.

| |a_00| |a_10| ... |a_n0| |
| |a_01| |a_11| ... |a_n1| |
| |... | |... | ... |... | |
| |a_0i| |a_1i| ... |a_ni| |
| |... | |... | ... |... | |

어디

  • n in ℕ,
  • a_ijiterable의 -th j요소에 해당합니다 i.

신청 후 transpose_finite_iterable우리는 얻을

| |a_00| |a_01| ... |a_0i| ... |
| |a_10| |a_11| ... |a_1i| ... |
| |... | |... | ... |... | ... |
| |a_n0| |a_n1| ... |a_ni| ... |

이러한 경우 파이썬 예 여기서 a_ij == j,n == 2

>>> from itertools import count
>>> iterable = [count(), count()]
>>> result = transpose_finite_iterable(iterable)
>>> next(result)
(0, 0)
>>> next(result)
(1, 1)

그러나 우리는 유한 iterables의 무한 iterable ( 우리의 경우 s) 이기 때문에 transpose_finite_iterable원래의 구조로 돌아 가기 위해 다시 사용할 수 없습니다 :iterableresulttuple

>>> transpose_finite_iterable(result)
... hangs ...
Traceback (most recent call last):
  File "...", line 1, in ...
  File "...", line 2, in transpose_finite_iterable
MemoryError

이 사건을 어떻게 다룰 수 있을까요?

… 그리고 여기에 온다 deque

우리는 docs of itertools.teefunction을 살펴본 후 약간의 수정으로 우리의 경우에 도움이 될 수있는 Python 레시피가 있습니다.

def transpose_finite_iterables(iterable):
    iterator = iter(iterable)
    try:
        first_elements = next(iterator)
    except StopIteration:
        return ()
    queues = [deque([element])
              for element in first_elements]

    def coordinate(queue):
        while True:
            if not queue:
                try:
                    elements = next(iterator)
                except StopIteration:
                    return
                for sub_queue, element in zip(queues, elements):
                    sub_queue.append(element)
            yield queue.popleft()

    return tuple(map(coordinate, queues))

점검 해보자

>>> from itertools import count
>>> iterable = [count(), count()]
>>> result = transpose_finite_iterables(transpose_finite_iterable(iterable))
>>> result
(<generator object transpose_finite_iterables.<locals>.coordinate at ...>, <generator object transpose_finite_iterables.<locals>.coordinate at ...>)
>>> next(result[0])
0
>>> next(result[0])
1

합성

이제 우리는 한정되어있는 반복 가능 객체 것들의 반복 가능 객체 작업을위한 일반 함수를 정의 할 수 있으며 다른 사람이 사용하여 잠재적으로 무한 functools.singledispatch장식을 같이

from collections import (abc,
                         deque)
from functools import singledispatch


@singledispatch
def transpose(object_):
    """
    Transposes given object.
    """
    raise TypeError('Unsupported object type: {type}.'
                    .format(type=type))


@transpose.register(abc.Iterable)
def transpose_finite_iterables(object_):
    """
    Transposes given iterable of finite iterables.
    """
    iterator = iter(object_)
    try:
        first_elements = next(iterator)
    except StopIteration:
        return ()
    queues = [deque([element])
              for element in first_elements]

    def coordinate(queue):
        while True:
            if not queue:
                try:
                    elements = next(iterator)
                except StopIteration:
                    return
                for sub_queue, element in zip(queues, elements):
                    sub_queue.append(element)
            yield queue.popleft()

    return tuple(map(coordinate, queues))


def transpose_finite_iterable(object_):
    """
    Transposes given finite iterable of iterables.
    """
    yield from zip(*object_)

try:
    transpose.register(abc.Collection, transpose_finite_iterable)
except AttributeError:
    # Python3.5-
    transpose.register(abc.Mapping, transpose_finite_iterable)
    transpose.register(abc.Sequence, transpose_finite_iterable)
    transpose.register(abc.Set, transpose_finite_iterable)

유한 한 비어 있지 않은 이터 러블에 대한 이진 연산자의 클래스에서 자체 역수 (수학자들은 이런 종류의 함수를 진화 “라고 부름)로 간주 할 수 있습니다 .


singledispatching 의 보너스로 다음 numpy과 같은 배열 을 처리 할 수 ​​있습니다.

import numpy as np
...
transpose.register(np.ndarray, np.transpose)

그런 다음 사용하십시오

>>> array = np.arange(4).reshape((2,2))
>>> array
array([[0, 1],
       [2, 3]])
>>> transpose(array)
array([[0, 2],
       [1, 3]])

노트

때문에 transpose누군가가 가지고 싶어하는 경우 반환 반복자와 tuplelist영업 이익처럼들 -이 함께 추가로 만들 수 있습니다 map내장 된 기능 과 같은

>>> original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
>>> tuple(map(list, transpose(original)))
(['a', 'b', 'c', 'd'], [1, 2, 3, 4])

광고

나는에 일반화 된 솔루션을 추가 한 lz패키지 에서 0.5.0처럼 사용할 수있는 버전

>>> from lz.transposition import transpose
>>> list(map(tuple, transpose(zip(range(10), range(10, 20)))))
[(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), (10, 11, 12, 13, 14, 15, 16, 17, 18, 19)]

추신

잠재적으로 무한 반복 가능한 무한 반복을 처리하는 솔루션은 (적어도 명백한) 없지만,이 경우는 덜 일반적입니다.


답변

그것을하는 또 다른 방법 일뿐이지만 여기에 많은 도움이되었습니다.

이 데이터 구조를 가지고 :

X=[1,2,3,4]
Y=['a','b','c','d']
XY=zip(X,Y)

를 야기하는:

In: XY
Out: [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]

압축을 풀고 원본으로 돌아가는 더 pythonic 방법은 내 의견으로는 다음과 같습니다.

x,y=zip(*XY)

그러나 이것은 튜플을 반환하므로 목록이 필요하면 다음을 사용할 수 있습니다.

x,y=(list(x),list(y))