Python'da zip (* [iter (s)] * n) nasıl çalışır?


103
s = [1,2,3,4,5,6,7,8,9]
n = 3

zip(*[iter(s)]*n) # returns [(1,2,3),(4,5,6),(7,8,9)]

Nasıl zip(*[iter(s)]*n)çalışır? Daha ayrıntılı bir kodla yazılmış olsaydı nasıl görünürdü?


1
nasıl çalıştığına da buradan bir göz atın: stackoverflow.com/questions/2202461/…
Matt Joiner

buradaki cevaplar yeterli değilse, buraya blog yazdım: telliott99.blogspot.com/2010/01/…
telliott99

7
Çok ilgi çekici olmasına rağmen, bu teknik Python'un temel "okunabilirlik" değerine aykırı olmalıdır!
Demis

Yanıtlar:


109

iter()bir dizi üzerinde yineleyicidir. miktarı , yani her bir elemanın olduğu uzunluk [x] * nlistesini içeren bir liste üretir . işlev çağrısı için bir diziyi bağımsız değişkenlere dönüştürür. Bu nedenle, aynı yineleyiciyi 3 kez'e geçiriyorsunuz ve her seferinde yineleyiciden bir öğe çekiyor.nxnx*argzip()

x = iter([1,2,3,4,5,6,7,8,9])
print zip(x, x, x)

1
Bilmekte fayda var : Bir yineleyici bir öğeyi yield(= returns) kullandığında, bu öğeyi "tüketilmiş" olarak hayal edebilirsiniz. Dolayısıyla yineleyici bir sonraki çağrıldığında, bir sonraki "tüketilmemiş" öğeyi verir.
winklerrr

46

Diğer harika cevaplar ve yorumlar, argüman açma ve zip () rollerini iyi açıklar .

As Ignacio ve ujukatzel söz hakkından, sen geçmek zip()aynı yineleyici üç referanslar ve zip()sipariş-gelen yineleyici her referansta tamsayılar-3-dizilerini yapar:

1,2,3,4,5,6,7,8,9  1,2,3,4,5,6,7,8,9  1,2,3,4,5,6,7,8,9
^                    ^                    ^            
      ^                    ^                    ^
            ^                    ^                    ^

Ve daha ayrıntılı bir kod örneği istediğiniz için:

chunk_size = 3
L = [1,2,3,4,5,6,7,8,9]

# iterate over L in steps of 3
for start in range(0,len(L),chunk_size): # xrange() in 2.x; range() in 3.x
    end = start + chunk_size
    print L[start:end] # three-item chunks

Değerlerini takip startve end:

[0:3) #[1,2,3]
[3:6) #[4,5,6]
[6:9) #[7,8,9]

FWIW, aşağıdaki map()ilk argümanla aynı sonucu elde edebilirsiniz None:

>>> map(None,*[iter(s)]*3)
[(1, 2, 3), (4, 5, 6), (7, 8, 9)]

Daha fazlası için zip()ve map(): http://muffinresearch.co.uk/archives/2007/10/16/python-transposing-lists-with-map-and-zip/


31

Bence tüm yanıtlarda gözden kaçan (muhtemelen yinelemelere aşina olanlar için açıktır), ancak diğerleri için o kadar açık olmayan bir şey -

Aynı yineleyiciye sahip olduğumuz için tüketilir ve kalan öğeler zip tarafından kullanılır. Öyleyse, örneğin yinelemeyi değil, listeyi kullanırsak.

l = range(9)
zip(*([l]*3)) # note: not an iter here, the lists are not emptied as we iterate 
# output 
[(0, 0, 0), (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5), (6, 6, 6), (7, 7, 7), (8, 8, 8)]

Yineleyiciyi kullanarak değerleri açar ve yalnızca kalan kullanılabilir durumda kalır, bu nedenle zip için 0 tüketildiğinde 1 kullanılabilir ve ardından 2 vb. Çok ince bir şey, ama oldukça zekice !!!


+1, beni kurtardın! Herkesin bunu bildiğini varsayarak diğer yanıtların bu hayati detayı atladığına inanamıyorum. Bu bilgileri içeren bir belgeye herhangi bir referans verebilir misiniz?
Snehasish Karmakar

9

iter(s) s için bir yineleyici döndürür.

[iter(s)]*n s için aynı yineleyicinin n katının bir listesini yapar.

Böylece, bunu yaparken zip(*[iter(s)]*n), sırayla listedeki üç yineleyiciden bir öğe çıkarır. Tüm yineleyiciler aynı nesne olduğundan, listeyi sadece n.


7
"Aynı listenin n yineleyicisi" değil, "n kez aynı yineleyici nesnesi". Farklı yineleyici nesneleri, aynı listede olsalar bile durumu paylaşmazlar.
Thomas Wouters

Teşekkürler, düzeltildi. Aslında "düşündüğüm" buydu, ama başka bir şey yazdım.
sttwister

6

Zip'i bu şekilde kullanmak için bir tavsiye. Uzunluğu eşit olarak bölünemezse listenizi kısaltır. Bu sorunu çözmek için , doldurma değerlerini kabul edebiliyorsanız, itertools.izip_longest'i kullanabilirsiniz . Veya bunun gibi bir şey kullanabilirsiniz:

def n_split(iterable, n):
    num_extra = len(iterable) % n
    zipped = zip(*[iter(iterable)] * n)
    return zipped if not num_extra else zipped + [iterable[-num_extra:], ]

Kullanım:

for ints in n_split(range(1,12), 3):
    print ', '.join([str(i) for i in ints])

Baskılar:

1, 2, 3
4, 5, 6
7, 8, 9
10, 11

3
Bu zaten itertoolstariflerde belgelenmiştir : docs.python.org/2/library/itertools.html#recipes grouper . Tekerleği yeniden icat etmeye gerek yok
jamylak

1

Yorumlayıcı veya piton neler olduğunu görmek için muhtemelen daha kolay olduğu ipythonile n = 2:

In [35]: [iter("ABCDEFGH")]*2
Out[35]: [<iterator at 0x6be4128>, <iterator at 0x6be4128>]

Yani, aynı yineleyici nesnesini işaret eden iki yineleyiciden oluşan bir listemiz var. Unutmayın iterbir nesne getirileri üzerinde yineleyici nesne ve bu senaryoda, aynı yineleyici nedeniyle iki kat *2piton sözdizimsel şeker. Yineleyiciler de yalnızca bir kez çalışır.

Bundan başka, zipIterables herhangi bir sayıda (alır sekansları olan Iterables ) ve giriş dizilerinin her birinin i'inci elemanından tuple oluşturur. Bizim durumumuzda her iki yineleyici de aynı olduğundan, zip, her 2 öğeli çıktı dizisi için aynı yineleyiciyi iki kez hareket ettirir.

In [41]: help(zip)
Help on built-in function zip in module __builtin__:

zip(...)
    zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]

    Return a list of tuples, where each tuple contains the i-th element
    from each of the argument sequences.  The returned list is truncated
    in length to the length of the shortest argument sequence.

Açma ( *) operatör olmasını sağlar yinelemeler bu durumda 2 öğeli bir tuple oluşturmak için yeterli girdi olmadığı kadar olan tükenmesi çalıştırmak.

Bu, herhangi bir değere genişletilebilir nve zip(*[iter(s)]*n)açıklandığı gibi çalışır.


Yavaş olduğum için üzgünüm. Ama "* 2 python sözdizimsel şekeri nedeniyle aynı yineleyici iki kez. Yineleyiciler de yalnızca bir kez çalışır." bölüm lütfen? Eğer öyleyse, sonuç neden [("A", "A") ....] değil? Teşekkürler.
Bowen Liu

@BowenLiu *, bir nesneyi kopyalamak için sadece rahatlıktır. Skalarlarla ve ardından listelerle deneyin. Ayrıca denemek print(*zip(*[iter("ABCDEFG")]*2))vs print(*zip(*[iter("ABCDEFG"), iter("ABCDEFG")])). Ardından, iki ifadedeki yineleyici nesnelerin gerçekte ne olduğunu görmek için ikisini daha küçük adımlara ayırmaya başlayın.
akhan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.