web-dev-qa-db-fra.com

Itérateur de la liste circulaire dans Python

Je dois parcourir une liste circulaire, éventuellement plusieurs fois, en commençant par le dernier élément visité.

Le cas d'utilisation est un pool de connexion. Un client demande la connexion, un itérateur vérifie si la connexion pointée est disponible et la renvoie, sinon elle boucle jusqu'à en trouver une disponible.

Existe-t-il un moyen pratique de le faire en Python?

78
user443854

Utilisez itertools.cycle , c'est son but exact:

from itertools import cycle

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

pool = cycle(lst)

for item in pool:
    print item,

Sortie:

a b c a b c ...

(Boucles pour toujours, évidemment)


Pour faire avancer manuellement l'itérateur et en extraire les valeurs une par une, appelez simplement next(pool) :

>>> next(pool)
'a'
>>> next(pool)
'b'
125
Lukas Graf

La bonne réponse est d'utiliser itertools.cycle . Mais supposons que cette fonction de bibliothèque n'existe pas. Comment le mettriez-vous en œuvre?

Utilisez un générateur :

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

Ensuite, vous pouvez soit utiliser une instruction for pour itérer indéfiniment, soit appeler next() pour obtenir la valeur unique suivante de l'itérateur du générateur:

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

Ou vous pouvez faire comme ça:

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

imprime a b c d e f a b c ... pour toujours

7
viky.pat

vous pouvez accomplir ceci avec la boucle append(pop()):

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

ou for i in range() boucle:

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

ou simplement:

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

while 1:
    for i in l:
       print i

qui impriment tous:

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

des trois, je serais sujet à l'approche append (pop ()) en tant que fonction

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]
2
litepresence

Si vous souhaitez utiliser n fois, implémentez la ncyclesrecette d'itertools :

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']
1
pylang

Vous avez besoin d'un itérateur personnalisé - Je vais adapter l'itérateur de cette réponse .

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
1
Ethan Furman