/ Sıkıştırılmış İşlevini (zip tersi) transpoze?

oy
363

Ben 2 maddelik dizilerini listesi var ve ilk her demet birinci öğe içerir ve ikinci liste ikinci öğeyi tutan nerede 2 listelerine dönüştürmek istiyorum.

Örneğin:

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

Bunu yapan bir yerleşik işlevi var mı?

Oluştur 21/08/2008 saat 03:29
kaynak kullanıcı
Diğer dillerde...                            


14 cevaplar

oy
576

zipKendi tersidir! Sağlanan özel * operatörünü kullanın.

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

Bu çalışma şekli arayarak olduğunu zipargümanlarla:

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

... argümanlar geçirilen dışında zip(bir tuplea dönüştürülen sonra) doğrudan, yani argüman sayısı çok büyük alma hakkında endişelenmenize gerek yoktur.

Cevap 21/08/2008 saat 03:36
kaynak kullanıcı

oy
24

Ayrıca yapabilirdi

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

Bu gerektiğini daha iyi ölçek. Özellikle Python gerekli olmadıkça Liste comprehensions genişleyen iyi yaparsa.

(Gibi arada, bu listeleri bir 2-tuple (çift), yerine dizilerini bir listesini yapar zipyapar.)

yerine gerçek listelerin jeneratörleri Tamam, bu durum o yapardı:

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

Her element için sormak kadar jeneratörler listesi üzerinden sesli yemek yok, ama diğer taraftan, orijinal listeye başvurular devam ediyorum.

Cevap 24/08/2008 saat 16:07
kaynak kullanıcı

oy
19

Eğer aynı uzunlukta olmayabilir listeleri varsa, Patrick Yanıt başına kadar zip kullanmak istemeyebilirsiniz. Bu çalışıyor:

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

Ancak farklı uzunluk listeleri ile zip kısa listenin uzunluğuna her öğeyi keser:

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

Sen Yok boş sonuçları doldurmak için hiçbir işlevi ile haritayı kullanabilirsiniz:

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

zip () olsa marjinal hızlıdır.

Cevap 02/01/2011 saat 11:14
kaynak kullanıcı

oy
12

Ben kullanmak ister zip(*iterable)şekilde benim programlarında (aradığınız kod parçası olan):

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

Ben bulmak unzipdaha okunabilir.

Cevap 01/03/2014 saat 13:00
kaynak kullanıcı

oy
2

Ben burada yazmak bu yüzden bana çok yardımcı ama bunu yapmanın tek başka bir yol:

Bu veri yapısını Having:

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

Sonuçlanan:

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

Bunu halletmek ve geri orijinal gitmek için daha pythonic yolu Bence bu biridir:

x,y=zip(*XY)

Bir dizi gerekirse kullanabilmesi Ama bu tuple döndürmek:

xy=(list(x),list(y))
Cevap 26/01/2016 saat 08:45
kaynak kullanıcı

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

Söz konusu olarak listelerin bir demet verir.

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

iki listeyi ayıklar.

Cevap 05/03/2016 saat 09:08
kaynak kullanıcı

oy
0

Diğer bir yolu düşünmek unzipveya transposesütunların bir liste halinde satırların listesini dönüştürmektedir.

pitchers = [('Nolan', 'Ryan'), ('Roger', 'Clements'), ('Schilling','Curt')]
first_names, last_names = zip(*pitchers)
In [45]: first_names
Out[45]: ('Nolan', 'Roger', 'Schilling')
In [46]: last_names
Out[46]: ('Ryan', 'Clements', 'Curt')
Cevap 18/04/2018 saat 01:27
kaynak kullanıcı

oy
1

O dizilerini döndürür (ve belleğin ton kullanabilirsiniz) bu yana, zip(*zipped)hüner bana, kullanışlı daha akıllı görünüyor.

İşte aslında size zip tersini verecek bir fonksiyon.

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
Cevap 11/06/2018 saat 12:35
kaynak kullanıcı

oy
-1

Bu, bir 4x2 başlığın içine 2x4 tuple devrik nasıl olduğunu.

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

sonuç

[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
Cevap 30/06/2018 saat 02:23
kaynak kullanıcı

oy
0

Önceki yanıtlardan hiçbiri verimli bir 'gerekli üretimini arttırmak listelerinin demet yerine bir dizilerini listesi . İlk amaçla kullanabilirsiniz tupleile map. Fark şudur:

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

Buna ek olarak, önceki çözümlerin çoğu Python 2.7, farz zipbir yineleyici yerine bir listesini döndürür.

Python 3.x için, aşağıdakiler gibi bir işleve sonucu geçmelisiniz listveya tupleyineleyici tüketmeye. Bellek verimli tekrarlayıcılara için, dış ihmal edilebilir listve tupleilgili çözümleri gerektirmektedir.

Cevap 23/08/2018 saat 16:36
kaynak kullanıcı

oy
0

İken zip(*seq)çok faydalıdır, Örneğin, ben bir milyondan fazla girişlerle bir koordinat sistemi ile çalışıyoruz. Bunun içinde geçirilecek bir değerler tuple yaratmak gibi çok uzun dizileri için uygun olmayabilir ve signifcantly daha hızlı oluşturmak için bulabilirsiniz şirketinden dizileri.

Genel yaklaşım böyle bir şey olacaktır:

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)

Ama, sonuç ne yapmak istediğinize bağlı koleksiyon seçimi büyük bir fark yaratabilir. Benim asıl kullanım durumunda, setleri ve hiçbir iç döngü kullanarak, tüm diğer yaklaşımlara göre belirgin ölçüde daha hızlıdır.

Diğerleri de belirtildiği gibi,, sen veri setleri ile yapıyoruz, eğer duyu yerine Numpy veya Pandalar koleksiyonlarını kullanmaya neden olabilir.

Cevap 26/09/2018 saat 13:08
kaynak kullanıcı

oy
2

naif yaklaşım

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

(örneğin, sekanslar gibi sonlu iterable için çalışıyor list/ tuple/ str) gibi şekillerle gösterilebilmektedir (potansiyel olarak sonsuz) Iterables arasında

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

nerede

  • n in ℕ,
  • a_ijkarşılık jelemanının inci iinci iterable,

ve uyguladıktan sonra transpose_finite_iterablealdığımız

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

Böyle davanın Python örneği nerede 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)

Ama biz kullanamaz transpose_finite_iterableorijinal yapısına dönmek için tekrar iterableçünkü result(sonlu Iterables sonsuz iterable olan tuplebizim durumumuzda ler):

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

Öyleyse nasıl bu durumda başa çıkabilirim?

... ve buraya gelir deque

Biz docs bakmak sonra itertools.teefonksiyonu , bazı değişikliklerle bizim durumumuzda yardımcı olabilir Python tarifi vardır

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

Hadi kontrol edelim

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

sentez

Şimdi sonlu olduğumuz Iterables olanlar Iterables ile çalışmak için genel işlevi tanımlayabilir ve başka olanları kullanarak potansiyel olarak sonsuz functools.singledispatchdekoratör gibi

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)

Kendi tersi olarak kabul edilebilir (matematikçiler fonksiyonları bu tür diyoruz "envolüsyonlar" sonlu boş olmayan Iterables üzerinde ikili operatörlerin sınıfında).


Bir avantaj olarak singledispatchbiz işleyebilir ing numpygibi diziler

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

ve sonra gibi kullanabilirsiniz

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

Not

Yana transposebirisi bir olmasını istiyorsa döner Yineleyiciler ve tuplebir listOP gibi s - bununla ayrıca yapılabilir mapdahili fonksiyonu gibi

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

reklâm

Ben genelleştirilmiş çözüm ekledik lzpaketlemek dan 0.5.0gibi kullanılabilir sürümü

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

PS

Orada potansiyel olarak sonsuz Iterables potansiyel olarak sonsuz iterable işlemek için çözüm (en azından bariz), ancak bu durumda olsa daha az yaygındır.

Cevap 21/12/2018 saat 10:46
kaynak kullanıcı

oy
0

Kullanmayı düşünün more_itertools.unzip .

Cevap 02/01/2019 saat 19:30
kaynak kullanıcı

oy
0
original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]

#unzip 
a1 , a2 = zip(*original)
#make tuple with two list
result=(list(a1),list(a2))
result

Sonuç = ([ 'a', 'b', c '', 'd'], [1, 2, 3, 4])

Cevap 12/04/2019 saat 02:18
kaynak kullanıcı

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more