programing

전치/해동 기능(zip 반대)

procenter 2022. 9. 21. 22:40
반응형

전치/해동 기능(zip 반대)

저는 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 ])

잘 확장될 거예요.특히 Python이 필요한 경우를 제외하고는 목록 통합을 확장하지 않는 것이 좋습니다.

TUPLE .를 들어, ('TUPLE'의 2태플(쌍)이 됩니다zip

실제 목록이 아닌 제너레이터가 정상인 경우 다음과 같이 됩니다.

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

생성기는 사용자가 각 요소를 요청할 때까지 목록을 대충 훑어보지 않지만, 다른 한편으로는 원래 목록에 대한 참조를 유지합니다.

사용하는 것을 좋아합니다.zip(*iterable) 있는 입니다) 라고 코드의 일부를 제 과 같이 되어 있습니다

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

unzip가독성이 향상됩니다.

같은 길이가 아닌 목록이 있는 경우 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, *[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', )])
[('a', 'b', 'c', 'd', 'e'), (1, 2, 3, 4, None)]

zip()이 약간 더 빠릅니다.

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

2개의 리스트를 언팩 합니다.

순진한 접근법

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_ij 대응하다ji할 수 있는 -반복하다

'이행'을 한 후transpose_finite_iterable

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

의 Python의 로서, Python은 다음과 같습니다.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)

못 요.transpose_finite_iterable iterableresult입니다.tuple( 、 [ ]

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

그럼 이 사건을 어떻게 처리해야 하죠?

여기...리고여여 있있있있있deque

기능 문서를 살펴본 후, 약간의 수정이 우리의 경우에 도움이 될 수 있는 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

합성

이제 우리는 다음과 같은 데코레이터를 사용하여 유한하고 잠재적으로 무한인 반복 가능의 반복 가능에 대한 일반적인 함수를 정의할 수 있습니다.

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)

이는 유한하고 비어 있지 않은 반복가능에 대한 이진 연산자의 클래스에서 그 자체의 역함수(이러한 함수를 "분해"라고 함)로 간주될 수 있다.


★★★★★★의 singledispatch가 수 .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하고, 가 '반복'을 tuplelists는 OP와 같습니다.이것은, 다음과 같은 빌트인 기능을 사용해 추가 가능합니다.

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

광고

패키지에 범용 솔루션을 추가했습니다.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')]

지퍼를 내리고 원래대로 돌아가는 더 비꼬는 방법은 다음과 같습니다.

x,y=zip(*XY)

그러나 이렇게 하면 태플이 반환되므로 목록이 필요한 경우 다음을 사용할 수 있습니다.

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

more_itertools.unzip을 사용하는 것을 검토합니다.

>>> from more_itertools import unzip
>>> original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
>>> [list(x) for x in unzip(original)]
[['a', 'b', 'c', 'd'], [1, 2, 3, 4]]     

위의 답변 중 어느 것도 튜플 목록이 아닌 목록 태플인 필요한 출력을 효율적으로 제공하지 않습니다.전자의 경우,tuplemap다음은 차이점입니다.

res1 = list(zip(*original))              # [('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
res2 = tuple(map(list, zip(*original)))  # (['a', 'b', 'c', 'd'], [1, 2, 3, 4])

이전 .여기서 Python 2.7은 Python 2.7입니다.zip는 반복자가 아닌 목록을 반환합니다.

3.를 Python 3.x의 .list ★★★★★★★★★★★★★★★★★」tuple리터레이터를 방전시킵니다.이 높은 반복기에서는 할 수 .list ★★★★★★★★★★★★★★★★★」tuple각 솔루션에 대한 요구.

numpy 어레이와 팬더가 선호될 수 있지만, 이 기능은 다음과 같은 동작을 모방합니다.zip(*args)라고 때unzip(args).

gener allows the from from from from allows 、 성 、 allows 、 allows 、 allows 、 allows allows allows 。 ★★★★★★★★★★★★★★★★★,zip3에서는 Python 3으로 .args이러한 가치를 통해 반복합니다.가치관을통해 반복될 때.

def unzip(items, cls=list, ocls=tuple):
    """Zip function in reverse.

    :param items: Zipped-like iterable.
    :type  items: iterable

    :param cls: Container factory. Callable that returns iterable containers,
        with a callable append attribute, to store the unzipped items. Defaults
        to ``list``.
    :type  cls: callable, optional

    :param ocls: Outer container factory. Callable that returns iterable
        containers. with a callable append attribute, to store the inner
        containers (see ``cls``). Defaults to ``tuple``.
    :type  ocls: callable, optional

    :returns: Unzipped items in instances returned from ``cls``, in an instance
        returned from ``ocls``.
    """
    # iter() will return the same iterator passed to it whenever possible.
    items = iter(items)

    try:
        i = next(items)
    except StopIteration:
        return ocls()

    unzipped = ocls(cls([v]) for v in i)

    for i in items:
        for c, v in zip(unzipped, i):
            c.append(v)

    return unzipped

목록 cointainers을 사용하려면, 단지 목록동인을사용하려면 단순히 실행.unzip(zipped), as,~하듯이

unzip(zip(["a","b","c"],[1,2,3])) == (["a","b","c"],[1,2,3])

deques, 또는 또는컨테이너 사용 스포츠용 기타 다른 어떠한 컨테이너 스포츠 데크를 사용하려면.append, 한 공장 기능.공장출하시 기능을 통과합니다.

from collections import deque

unzip([("a",1),("b",2)], deque, list) == [deque(["a","b"]),deque([1,2])]

( 꾸미(장식)cls및/또는 및/또는main_cls마이크로 경영 컨테이너 초기화려면 잠시 최종다고 주장하는 성명에서 상류에 있다.)이라고 보여 주었다.위의 최종 어설션 스테이트먼트에서 간략하게 나타난 바와 같이,컨테이너초기화를 미세하게 관리합니다.

때문에 반환합니다 tuples,(메모리톤을 사용할 수 있).zip(*zipped)트릭은 유용하기보다 영리해 보입니다.

여기 zip의 역기능이 있습니다.

def unzip(zipped):
    """Inverse of built-in zip function.
    Args:
        zipped: a list of tuples

    Returns:
        a tuple of lists

    Example:
        a = [1, 2, 3]
        b = [4, 5, 6]
        zipped = list(zip(a, b))

        assert zipped == [(1, 4), (2, 5), (3, 6)]

        unzipped = unzip(zipped)

        assert unzipped == ([1, 2, 3], [4, 5, 6])

    """

    unzipped = ()
    if len(zipped) == 0:
        return unzipped

    dim = len(zipped[0])

    for i in range(dim):
        unzipped = unzipped + ([tup[i] for tup in zipped], )

    return unzipped

한편, 「 」는, 「 」, 「 」의 사이에zip(*seq)는 매우 유용하며, 전달되는 값의 태플이 생성되므로 매우 긴 시퀀스에 적합하지 않을 수 있습니다.예를 들어, 저는 100만 개 이상의 엔트리를 가진 좌표계를 이용해 직접 시퀀스를 작성하는 것이 상당히 빠르다는 것을 알게 되었습니다.

일반적인 접근방식은 다음과 같습니다.

from collections import deque
seq = ((a1, b1, …), (a2, b2, …), …)
width = len(seq[0])
output = [deque(len(seq))] * width # preallocate memory
for element in seq:
    for s, item in zip(output, element):
        s.append(item)

그러나 결과를 어떻게 처리하느냐에 따라 수집 선택이 크게 달라질 수 있습니다.실제 사용 사례에서는 내부 루프를 사용하지 않고 세트를 사용하는 것이 다른 모든 접근 방식보다 현저하게 빠릅니다.

그리고 다른 사람들이 지적했듯이 데이터셋을 사용하는 경우 Numpy 또는 Panda 컬렉션을 사용하는 것이 현명할 수 있습니다.

다음은 원하는 출력을 생성하는 간단한 한 줄의 답변은 다음과 같습니다.

original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
list(zip(*original))
# [('a', 'b', 'c', 'd'), (1, 2, 3, 4)]

언급URL : https://stackoverflow.com/questions/19339/transpose-unzip-function-inverse-of-zip

반응형