从列表中弹出随机元素最具 Python 风格的方法是什么?
- 2025-03-05 09:15:00
- admin 原创
- 79
问题描述:
假设我有一个长度未知的列表x
,我想从中随机弹出一个元素,以便列表之后不包含该元素。 最符合 Python 风格的方法是什么?
pop
我可以使用、random.randint
和的相当不方便的组合来实现这一点len
,并且希望看到更短或更好的解决方案:
import random
x = [1,2,3,4,5,6]
x.pop(random.randint(0,len(x)-1))
我想要实现的是从列表中连续弹出随机元素。(即,随机弹出一个元素并将其移动到字典中,随机弹出另一个元素并将其移动到另一个字典中,...)
请注意,我使用的是 Python 2.6,并且没有通过搜索功能找到任何解决方案。
解决方案 1:
首先,你做的事情看起来不太符合 Python 风格。你不应该从列表中间删除内容,因为据我所知,所有 Python 实现中列表都是作为数组实现的,所以这是一个O(n)
操作。
如果您确实需要此功能作为算法的一部分,则应检查支持blist
从中间有效删除的数据结构。
在纯 Python 中,如果不需要访问剩余元素,您可以先对列表进行打乱,然后对其进行迭代:
lst = [1,2,3]
random.shuffle(lst)
for x in lst:
# ...
如果你真的需要余数(在我看来,这有点代码味道),至少你pop()
现在可以从列表末尾获取(速度很快!):
while lst:
x = lst.pop()
# do something with the element
一般来说,如果您使用更具功能性的风格,而不是改变状态(就像您对列表所做的那样),那么您通常可以更优雅地表达您的程序。
解决方案 2:
你不会比这更好,但这里有一点改进:
x.pop(random.randrange(len(x)))
文件random.randrange()
:
random.randrange([start], stop[, step])
从 中返回一个随机选择的元素
range(start, stop, step)
。这相当于choice(range(start, stop, step))
,但实际上并不构建范围对象。
解决方案 3:
如果列表其余元素的顺序无关紧要,则从列表中删除随机索引处的单个元素:
import random
L = [1,2,3,4,5,6]
i = random.randrange(len(L)) # get random index
L[i], L[-1] = L[-1], L[i] # swap with the last element
x = L.pop() # pop last element O(1)
交换用于避免从列表中间删除时的 O(n) 行为。
解决方案 4:
头对头比较 ⚖
尽管许多答案建议使用random.shuffle(x)
,但它在处理大数据时非常慢。当启用随机播放时,元素x.pop()
列表所需的时间10000
约为。当禁用随机播放时,速度是6 seconds
`0.2s`
fastest
测试了上述所有给出的方法后,发现该方法是由@jfs 编写的,因为只触及了一个项目。
import random
L = [1,"2",[3],(4),{5:"6"},'etc'] #you can take mixed or pure list
i = random.randrange(len(L)) # get random index
L[i], L[-1] = L[-1], L[i] # swap with the last element
x = L.pop() # pop last element O(1)
或者增强(niklas answer),对所有元素执行random.shuffle() (成本高昂),可以是一行:
扫码咨询,免费领取项目管理大礼包!