【发布时间】:2012-09-25 16:37:51
【问题描述】:
我需要一个功能类似于集合(快速插入、删除和成员资格检查)但能够返回随机值的 Python (2.7) 对象。以前在 stackoverflow 上提出的问题的答案如下:
import random
random.sample(mySet, 1)
但这对于大型集合来说非常慢(它在 O(n) 时间内运行)。
其他解决方案不够随机(它们依赖于 python 集合的内部表示,这会产生一些非常非随机的结果):
for e in mySet:
break
# e is now an element from mySet
我编写了自己的基本类,它具有恒定的时间查找、删除和随机值。
class randomSet:
def __init__(self):
self.dict = {}
self.list = []
def add(self, item):
if item not in self.dict:
self.dict[item] = len(self.list)
self.list.append(item)
def addIterable(self, item):
for a in item:
self.add(a)
def delete(self, item):
if item in self.dict:
index = self.dict[item]
if index == len(self.list)-1:
del self.dict[self.list[index]]
del self.list[index]
else:
self.list[index] = self.list.pop()
self.dict[self.list[index]] = index
del self.dict[item]
def getRandom(self):
if self.list:
return self.list[random.randomint(0,len(self.list)-1)]
def popRandom(self):
if self.list:
index = random.randint(0,len(self.list)-1)
if index == len(self.list)-1:
del self.dict[self.list[index]]
return self.list.pop()
returnValue = self.list[index]
self.list[index] = self.list.pop()
self.dict[self.list[index]] = index
del self.dict[returnValue]
return returnValue
有没有更好的实现,或者对这段代码有什么大的改进?
【问题讨论】:
-
当你需要集合操作的东西时,为什么不直接使用列表并将其转换为集合呢? ...
-
这允许您在不影响性能的情况下交叉添加元素和选择元素。你的现实生活场景真的遵循这种模式吗?如果您可以预先添加所有元素,则可以从一个集合开始,然后在抓取随机元素之前转换为一个列表。
-
因为对于大型列表来说这非常慢(在 O(n) 时间内运行)。
-
@GrantS:你的意思是创建列表很慢?那只需要做一次。这并不比在课堂上创建列表和字典慢。
-
@GrantS:如果您正在使用 Python 2.x,为了更大的利益:从“对象”或其他新样式库继承。不要使用旧式类(通过不声明超类) - 难以调试的问题可能会严重伤害您