ตัววนซ้ำรายการแบบวงกลมใน Python


106

ฉันจำเป็นต้องวนซ้ำรายการแบบวงกลมอาจจะหลาย ๆ ครั้งทุกครั้งที่เริ่มต้นด้วยรายการที่เยี่ยมชมล่าสุด

กรณีการใช้งานคือพูลการเชื่อมต่อ ไคลเอนต์ขอการเชื่อมต่อตัววนซ้ำจะตรวจสอบว่ามีการเชื่อมต่อแบบชี้ไปที่พร้อมใช้งานหรือไม่และส่งคืนหรือไม่เช่นนั้นจะวนซ้ำจนกว่าจะพบการเชื่อมต่อที่พร้อมใช้งาน

มีวิธีทำใน Python อย่างเรียบร้อยหรือไม่?

คำตอบ:


169

ใช้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 ...

(ลูปตลอดไปชัด ๆ )


ในการเลื่อนตัววนซ้ำด้วยตนเองและดึงค่าจากมันทีละรายการเพียงโทรnext(pool):

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

2
คุณกำลังพิมพ์รายการแบบวนซ้ำ สิ่งที่ฉันต้องการออกจากลูปแล้วกลับมาใหม่ในภายหลัง (อยากเริ่มจากจุดที่ค้างไว้)
user443854

7
@ user443854 ใช้pool.next()เพื่อรับรายการถัดไปจากรอบ
Jacob Krall

4
@ user443854 FWIW นี่เป็นคำตอบที่ดีกว่าของฉันมาก ไม่มีเหตุผลที่จะต้องนำฟังก์ชันไลบรารีไปใช้ใหม่อีกครั้ง!
Jacob Krall

5
pool.next () ไม่ได้ผลสำหรับฉันถัดไป (พูล) เท่านั้น อาจเป็นเพราะ Python 3?
fjsj

6
@fjsj ถูกต้องใน Python 3 คุณต้องใช้next(iterator)(ซึ่ง BTW ก็ใช้ได้ดีกับ Python 2.x ดังนั้นจึงเป็นรูปแบบบัญญัติที่ควรใช้) โปรดดูที่generator.next () มองเห็นได้ใน python 3.0 หรือไม่ สำหรับคำอธิบายเชิงลึกเพิ่มเติม อัปเดตคำตอบของฉันตามนั้น
Lukas Graf

56

คำตอบที่ถูกต้องคือการใช้itertools.cycle แต่สมมติว่าไม่มีฟังก์ชันไลบรารี คุณจะใช้มันอย่างไร?

ใช้เครื่องกำเนิดไฟฟ้า :

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

จากนั้นคุณสามารถใช้forคำสั่งเพื่อวนซ้ำได้ไม่ จำกัด หรือคุณสามารถเรียกnext()เพื่อรับค่าถัดไปจากตัวสร้างซ้ำตัวสร้าง:

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

ดี! จะรู้ได้อย่างไรว่าจะเริ่มใหม่เมื่อรายการหมด?
user443854

1
@ user443854 while Trueวิธีที่จะทำซ้ำตลอดไป
Jacob Krall

3
@juanchopanza: อ๋อ; itertools.cycleเป็นคำตอบที่ดีกว่า นี่แสดงให้เห็นว่าคุณสามารถเขียนฟังก์ชันเดียวกันได้อย่างไรหากitertoolsไม่สามารถใช้งานได้ :)
Jacob Krall

เครื่องกำเนิดไฟฟ้าอย่างง่ายยังบันทึกสำเนาของแต่ละองค์ประกอบด้วยitertools.cycleหรือไม่ หรือเครื่องกำเนิดไฟฟ้าธรรมดาจะเป็นการออกแบบที่มีประสิทธิภาพหน่วยความจำมากกว่า? ตามcycleเอกสาร :Note, this member of the toolkit may require significant auxiliary storage (depending on the length of the iterable).
2559

2
@dthor เครื่องกำเนิดไฟฟ้านี้จะสร้างรายการที่มีองค์ประกอบสามอย่างและมีผู้รู้อยู่เหนือสิ่งนั้นจากนั้นทำลายรายการและสร้างรายการใหม่อย่างถาวร เอกสารประกอบดังกล่าวcycleแสดงให้เห็นว่าอินพุตที่ทำซ้ำได้จะถูกแปลงเป็นlistก่อนที่ตัวสร้างจะเริ่มทำงานเนื่องจากiterableเป็นเพียง "ดีสำหรับการส่งผ่านชุดค่าเดียว"
Jacob Krall

9

หรือคุณสามารถทำได้ดังนี้:

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 ... ตลอดไป


4

คุณสามารถทำได้ด้วยappend(pop())ลูป:

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

หรือfor i in range()วนซ้ำ:

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

หรือเพียงแค่:

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

while True:
    for i in l:
       print i

ทั้งหมดที่พิมพ์:

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

ในสามคนฉันมักจะใช้วิธีผนวก (ป๊อป ()) เป็นฟังก์ชัน

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

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

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

1
การอัปเกรดสิ่งนี้เนื่องจากช่วยให้ฉันมีกรณีการใช้งานที่แตกต่างไปจากเดิมโดยสิ้นเชิงโดยที่ฉันต้องการทำซ้ำในรายการหลาย ๆ ครั้งโดยแต่ละครั้งที่องค์ประกอบเริ่มต้นจะเลื่อนไปหนึ่งขั้น กรณีการใช้งานของฉันคือการย้ำผู้เล่นในเกมโป๊กเกอร์โดยให้ดีลเลอร์ดึงผู้เล่นหนึ่งคนไปข้างหน้าในแต่ละรอบ
Johan

3

หากคุณต้องการหมุนเวียนnเวลาให้ใช้ncycles สูตร 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']

2

คุณต้องมีตัวทำซ้ำที่กำหนดเอง - ฉันจะปรับตัวทำซ้ำจากคำตอบนี้

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

0

เพื่อหลีกเลี่ยงการวนซ้ำที่ไม่มีที่สิ้นสุดฉันได้ใช้ความยาวของอาร์เรย์เพื่อวนซ้ำจนกว่าขนาดของรายการจะเป็นสองเท่าคุณสามารถใช้เงื่อนไขก่อนของคุณเองได้แนวคิดคือการหลีกเลี่ยงการวนซ้ำที่ไม่มีที่สิ้นสุด

#Implement Circular Linked List
from itertools import cycle
list=[1,2,3,4,5]
lstlength=len(list)*2
print(lstlength)
pool=cycle(list)
i=0
#To avoid infinite loop break when you have iterated twice size of the list
for items in pool:
    print(items)
    if i >lstlength:
        break
    i += 1
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.