Python'da dairesel liste yineleyici


99

Her seferinde en son ziyaret edilen öğeden başlayarak, muhtemelen birçok kez döngüsel bir listeyi yinelemem gerekiyor.

Kullanım durumu bir bağlantı havuzudur. Bir istemci bağlantı ister, bir yineleyici işaretli bağlantının mevcut olup olmadığını kontrol eder ve onu döndürür, aksi takdirde uygun olanı bulana kadar döngü yapar.

Python'da bunu yapmanın düzgün bir yolu var mı?

Yanıtlar:


159

Kullanın itertools.cycle, tam amacı bu:

from itertools import cycle

lst = ['a', 'b', 'c']

pool = cycle(lst)

for item in pool:
    print item,

Çıktı:

a b c a b c ...

(Belli ki sonsuza kadar döngüler)


Yineleyiciyi manuel olarak ilerletmek ve ondan değerleri birer birer almak için şunu arayın next(pool):

>>> next(pool)
'a'
>>> next(pool)
'b'

1
Öğeleri bir döngü halinde yazdırıyorsunuz. Döngüden çıkmak ve daha sonra geri dönmek istediğim şey? (Kaldığım yerden başlamak istiyorum).
user443854

7
@ user443854 döngüden pool.next()sonraki tek öğeyi almak için kullan
Jacob Krall

4
@ user443854 FWIW Bu benimkinden çok daha iyi bir cevap. Kütüphane işlevlerini yeniden uygulamaya koymaya gerek yok!
Jacob Krall

5
pool.next () benim için işe yaramadı, sadece sonraki (havuz). Muhtemelen Python 3 yüzünden mi?
fjsj

6
Doğru olan @fjsj, Python 3'te kullanmanız gerekir next(iterator)(BTW , Python 2.x'te de gayet iyi çalışır ve bu nedenle kullanılması gereken kanonik formdur). Bkz piton 3.0 görünür Is generator.next ()? daha derinlemesine bir açıklama için. Cevabımı buna göre güncelledim.
Lukas Graf

54

Doğru cevap itertools.cycle kullanmaktır. . Ancak, kütüphane işlevinin olmadığını varsayalım. Nasıl uygularsın?

Bir jeneratör kullanın :

def circular():
    while True:
        for connection in ['a', 'b', 'c']:
            yield connection

Ardından, forsonsuz yineleme yapmak için bir ifade kullanabilir veya oluşturucu next()yineleyiciden bir sonraki tek değeri almak için arama yapabilirsiniz :

connections = circular()
next(connections) # 'a'
next(connections) # 'b'
next(connections) # 'c'
next(connections) # 'a'
next(connections) # 'b'
next(connections) # 'c'
next(connections) # 'a'
#....

Güzel! Liste bittiğinde baştan başlamayı nasıl biliyor?
user443854

1
@ user443854 while Truesonsuza kadar tekrar etmenin yolu
Jacob Krall

2
@juanchopanza: Evet; itertools.cycledaha iyi bir cevap. Bu, itertoolsmevcut değilse aynı işlevi nasıl yazabileceğinizi gösterir :)
Jacob Krall

Basit oluşturucu da her bir öğenin bir kopyasını itertools.cyclekaydediyor mu? Veya basit oluşturucu, bellek açısından daha verimli bir tasarım mı olurdu? cycleDokümanlar başına :Note, this member of the toolkit may require significant auxiliary storage (depending on the length of the iterable).
dthor

2
@dthor bu oluşturucu, üzerinde üç öğeli ve okur yazar olan bir liste oluşturur, ardından listeyi yok eder ve kalıcı olarak yeni bir tane oluşturur. Bu dokümantasyon, cycleyinelenebilir girdinin listüreteci başlamadan önce dönüştürüldüğünü ima eder , çünkü iterableyalnızca "değerler kümesinden bir geçiş için iyidir".
Jacob Krall

9

Veya bunun gibi yapabilirsiniz:

conn = ['a', 'b', 'c', 'd', 'e', 'f']
conn_len = len(conn)
index = 0
while True:
    print(conn[index])
    index = (index + 1) % conn_len

abcdefab c yazdırır ... sonsuza kadar


3

bunu append(pop())döngü ile başarabilirsiniz :

l = ['a','b','c','d']
while 1:
    print l[0]
    l.append(l.pop(0))

veya for i in range()döngü:

l = ['a','b','c','d']
ll = len(l)
while 1:
    for i in range(ll):
       print l[i]

ya da sadece:

l = ['a','b','c','d']

while 1:
    for i in l:
       print i

tümü basılı:

>>>
a
b
c
d
a
b
c
d
...etc.

bir işlev olarak append (pop ()) yaklaşımına eğilimli olacağım

servers = ['a','b','c','d']

def rotate_servers(servers):
    servers.append(servers.pop(0))
    return servers

while 1:
    servers = rotate_servers(servers)
    print servers[0]

Bunu desteklemek, çünkü her seferinde başlangıç ​​öğesinin bir adım ilerlediği bir listeyi birkaç kez yinelemek istediğim tamamen farklı bir kullanım senaryosunda bana yardımcı oldu. Benim kullanım durumum, bir poker oyununda oyuncular üzerinde yinelemek, krupiyeyi her turda bir oyuncu öne doğru ilerletmek.
Johan

2

Özel bir yineleyiciye ihtiyacınız var - yineleyiciyi bu yanıttan uyarlayacağım .

from itertools import cycle

class ConnectionPool():
    def __init__(self, ...):
        # whatever is appropriate here to initilize
        # your data
        self.pool = cycle([blah, blah, etc])
    def __iter__(self):
        return self
    def __next__(self):
        for connection in self.pool:
            if connection.is_available:  # or however you spell it
                return connection

2

Döngü nsüreleri istiyorsanız , ncycles itertools tarifini uygulayın :

from itertools import chain, repeat


def ncycles(iterable, n):
    "Returns the sequence elements n times"
    return chain.from_iterable(repeat(tuple(iterable), n))


list(ncycles(["a", "b", "c"], 3))
# ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c']
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.