如何从集中检索一个元素而不删除它?
时间:2020-03-05 18:52:29 来源:igfitidea点击:
假设以下内容:
>>> s = set([1, 2, 3])
如何在不执行s.pop()的情况下从s中获得一个值(任何值)?我想将该项目保留在集合中,直到我确定可以将其删除为止,只有在异步调用另一台主机之后,我才能确定该项目。
快速而肮脏:
>>> elem = s.pop() >>> s.add(elem)
但是我们知道更好的方法吗?理想情况下是恒定时间。
解决方案
回答
不需要复制整个集合的两个选项:
for e in s: break # e is now an element from s
或者...
e = next(iter(s))
但是总的来说,集合不支持索引或者切片。
回答
另一种选择是将字典与不需要的值一起使用。例如。,
poor_man_set = {} poor_man_set[1] = None poor_man_set[2] = None poor_man_set[3] = None ...
我们可以将键视为一个集合,但它们只是一个数组:
keys = poor_man_set.keys() print "Some key = %s" % keys[0]
这种选择的副作用是代码将与旧的,预置的Python版本向后兼容。这可能不是最佳答案,但这是另一种选择。
编辑:我们甚至可以执行以下操作来隐藏使用dict而不是数组或者集合的事实:
poor_man_set = {} poor_man_set[1] = None poor_man_set[2] = None poor_man_set[3] = None poor_man_set = poor_man_set.keys()
回答
由于我们需要一个随机元素,因此也可以使用:
>>> import random >>> s = set([1,2,3]) >>> random.sample(s, 1) [2]
该文档似乎没有提到random.sample
的性能。从包含大量列表和大量集合的非常快速的实证检验来看,列表似乎是恒定时间,但集合却并非如此。同样,对集合的迭代也不是随机的。顺序不确定,但可以预测:
>>> list(set(range(10))) == range(10) True
如果随机性很重要,并且我们需要在恒定时间内(大集合)需要一堆元素,那么我将使用random.sample
并首先转换为列表:
>>> lst = list(s) # once, O(len(s))? ... >>> e = random.sample(lst, 1)[0] # constant time
回答
最少的代码是:
>>> s = set([1, 2, 3]) >>> list(s)[0] 1
显然,这将创建一个包含该集合的每个成员的新列表,因此如果集合很大,就不会很大。
回答
我使用编写的实用程序函数。它的名称有点误导,因为它暗示它可能是随机物品或者类似物品。
def anyitem(iterable): try: return iter(iterable).next() except StopIteration: return None
回答
为了提供不同方法背后的一些时序图,请考虑以下代码。
get()是我对Python的setobject.c的自定义添加,只是一个pop()而没有删除该元素。
from timeit import * stats = ["for i in xrange(1000): iter(s).next() ", "for i in xrange(1000): \n\tfor x in s: \n\t\tbreak", "for i in xrange(1000): s.add(s.pop()) ", "for i in xrange(1000): s.get() "] for stat in stats: t = Timer(stat, setup="s=set(range(100))") try: print "Time for %s:\t %f"%(stat, t.timeit(number=1000)) except: t.print_exc()
输出为:
$ ./test_get.py Time for for i in xrange(1000): iter(s).next() : 0.433080 Time for for i in xrange(1000): for x in s: break: 0.148695 Time for for i in xrange(1000): s.add(s.pop()) : 0.317418 Time for for i in xrange(1000): s.get() : 0.146673
这意味着for / break解决方案是最快的(有时比自定义get()解决方案更快)。