web-dev-qa-db-ja.com

Pythonの循環リストイテレータ

最後にアクセスしたアイテムから開始するたびに、おそらく何度も循環リストを反復処理する必要があります。

ユースケースは接続プールです。クライアントは接続を要求し、イテレータはポイントされた接続が使用可能かどうかを確認してそれを返し、そうでない場合は使用可能な接続が見つかるまでループします。

Pythonでそれを行うきちんとした方法はありますか?

78
user443854

itertools.cycle を使用します。これがまさにその目的です。

from itertools import cycle

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

pool = cycle(lst)

for item in pool:
    print item,

出力:

a b c a b c ...

(明らかに永遠にループします)


手動でイテレータを進め、イテレータから値を1つずつ取得するには、単に next(pool) を呼び出します。

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

正解は itertools.cycle を使用することです。しかし、ライブラリ関数が存在しないと仮定しましょう。どのように実装しますか?

generator を使用します。

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

次に、 for ステートメントを使用して無限に反復するか、 next() を呼び出してジェネレーターイテレーターから次の1つの値を取得します。

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

または、次のようにできます:

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

a b c d e f a b c ... foreverを出力します

7
viky.pat

append(pop())ループでこれを達成できます:

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

またはfor i in range()ループ:

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

または単に:

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

while 1:
    for i in l:
       print i

すべての印刷:

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

3つのうち、関数としてappend(pop())アプローチになりやすい

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

n回循環させる場合は、ncyclesitertools recipe を実装します。

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

カスタムのイテレータが必要です- this answer からイテレータを適応させます。

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