如何在删除项目时循环 Python 列表,直到剩下 none
How to cycle over a Python list while removing items until there are none left
标准库中的cycle迭代器没有insert和remove方法,所以一旦实例化就不能修改值了:
from itertools import cycle
import random
players = cycle([1, 2, 3])
while len(players) > 0:
player = next(player)
print(f"Player {player}'s turn")
if random.randint(0, 6) == 1:
players.remove(player)
# Raises TypeError: 'object of type 'itertools.cycle' has no len()'
这并不奇怪,因为它遍历列表参数,存储每个项目,并且 'know' 在完成第一个循环之前不会 'know' 列表的全部内容。
是否有替代方案可以实现以下行为:
players = [1, 2, 3]
i = 0
while len(players) > 0:
i = i % len(players)
player = players[i]
print(f"Player {player}'s turn")
if random.randint(0, 6) == 1:
players.remove(player)
else:
i += 1
我知道这是可行的,但我想知道我是否缺少更简单的方法。
我考虑过每次删除项目后重新构建循环的方法,但这也会将位置重置为循环的开头:
from itertools import cycle
players = [1, 2, 3]
while len(players) > 0:
for player in cycle(players): # Problem: always starts with player 1
print(f"Player {player}'s turn")
if random.randint(0, 6) == 1:
players.remove(player)
break
但是,我想不出一个简单的方法来在删除元素后移动到下一个玩家。
您可以使用 pop() 来使用列表项。
players = [1, 2, 3]
while players:
player = players.pop()
print('player:', player)
这是解决问题的一种方法。它删除了玩家,然后 re-orders 列表,所以下一个玩家会出现。
from itertools import cycle
players = [1, 2, 3]
while len(players) > 0:
for player in cycle(players):
print(f"Player {player}'s turn")
if random.randint(0, 6) == 1:
i = players.index(player)
# Remove player and re-order list
players = players[i+1:] + players[:i]
break
或者,使用 pop 的类似事情:
from itertools import cycle, islice
players = [1, 2, 3]
i = 0
while len(players) > 0:
for player in islice(cycle(players), i, None):
print(f"Player {player}'s turn")
if random.randint(0, 6) == 1:
i = players.index(player)
# Remove player
players.pop(i)
break
如果玩家 ID 是唯一的,您可以在使用 itertools.cycle()
时维护一组要跳过的元素:
import random
from itertools import cycle
players = [1, 2, 3]
players_to_skip = set()
player_iterator = cycle(players)
while len(players_to_skip) < len(players):
current_player = next(player_iterator)
if current_player in players_to_skip:
continue
print(f"Player {current_player}'s turn")
if random.randint(0, 6) == 1:
players_to_skip.add(current_player)
考虑到目前的选项,我认为忘记循环并在 while 循环中嵌套一个 for 循环可能更容易,同时记住制作一个可迭代的 for 循环的副本,这样它就不会得到修改的。 前提是每次迭代只移除当前玩家这应该有效:
players = [1, 2, 3]
while len(players) > 0:
for player in players.copy():
print(f"Player {player}'s turn")
if random.randint(0, 6) == 1:
players.remove(player)
标准库中的cycle迭代器没有insert和remove方法,所以一旦实例化就不能修改值了:
from itertools import cycle
import random
players = cycle([1, 2, 3])
while len(players) > 0:
player = next(player)
print(f"Player {player}'s turn")
if random.randint(0, 6) == 1:
players.remove(player)
# Raises TypeError: 'object of type 'itertools.cycle' has no len()'
这并不奇怪,因为它遍历列表参数,存储每个项目,并且 'know' 在完成第一个循环之前不会 'know' 列表的全部内容。
是否有替代方案可以实现以下行为:
players = [1, 2, 3]
i = 0
while len(players) > 0:
i = i % len(players)
player = players[i]
print(f"Player {player}'s turn")
if random.randint(0, 6) == 1:
players.remove(player)
else:
i += 1
我知道这是可行的,但我想知道我是否缺少更简单的方法。
我考虑过每次删除项目后重新构建循环的方法,但这也会将位置重置为循环的开头:
from itertools import cycle
players = [1, 2, 3]
while len(players) > 0:
for player in cycle(players): # Problem: always starts with player 1
print(f"Player {player}'s turn")
if random.randint(0, 6) == 1:
players.remove(player)
break
但是,我想不出一个简单的方法来在删除元素后移动到下一个玩家。
您可以使用 pop() 来使用列表项。
players = [1, 2, 3]
while players:
player = players.pop()
print('player:', player)
这是解决问题的一种方法。它删除了玩家,然后 re-orders 列表,所以下一个玩家会出现。
from itertools import cycle
players = [1, 2, 3]
while len(players) > 0:
for player in cycle(players):
print(f"Player {player}'s turn")
if random.randint(0, 6) == 1:
i = players.index(player)
# Remove player and re-order list
players = players[i+1:] + players[:i]
break
或者,使用 pop 的类似事情:
from itertools import cycle, islice
players = [1, 2, 3]
i = 0
while len(players) > 0:
for player in islice(cycle(players), i, None):
print(f"Player {player}'s turn")
if random.randint(0, 6) == 1:
i = players.index(player)
# Remove player
players.pop(i)
break
如果玩家 ID 是唯一的,您可以在使用 itertools.cycle()
时维护一组要跳过的元素:
import random
from itertools import cycle
players = [1, 2, 3]
players_to_skip = set()
player_iterator = cycle(players)
while len(players_to_skip) < len(players):
current_player = next(player_iterator)
if current_player in players_to_skip:
continue
print(f"Player {current_player}'s turn")
if random.randint(0, 6) == 1:
players_to_skip.add(current_player)
考虑到目前的选项,我认为忘记循环并在 while 循环中嵌套一个 for 循环可能更容易,同时记住制作一个可迭代的 for 循环的副本,这样它就不会得到修改的。 前提是每次迭代只移除当前玩家这应该有效:
players = [1, 2, 3]
while len(players) > 0:
for player in players.copy():
print(f"Player {player}'s turn")
if random.randint(0, 6) == 1:
players.remove(player)