假设如下:
>>> s = set([1, 2, 3])
我如何得到一个值(任何值)不做s.pop()?我希望将项目留在集合中,直到我确定可以删除它—只有在对另一个主机进行异步调用之后才能确定这一点。
又快又脏:
>>> elem = s.pop()
>>> s.add(elem)
但你知道更好的办法吗?理想情况是在常数时间内。
假设如下:
>>> s = set([1, 2, 3])
我如何得到一个值(任何值)不做s.pop()?我希望将项目留在集合中,直到我确定可以删除它—只有在对另一个主机进行异步调用之后才能确定这一点。
又快又脏:
>>> elem = s.pop()
>>> s.add(elem)
但你知道更好的办法吗?理想情况是在常数时间内。
当前回答
两个不需要复制整个集合的选项:
for e in s:
break
# e is now an element from s
还是……
e = next(iter(s))
但一般来说,集合不支持索引或切片。
其他回答
为了提供不同方法背后的时间图,考虑以下代码。 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()解决方案还要快)。
我用的是我写的效用函数。它的名字有点误导,因为它暗示它可能是一个随机的项目或类似的东西。
def anyitem(iterable):
try:
return iter(iterable).next()
except StopIteration:
return None
s.copy().pop()怎么样?我还没有计时,但应该可以,而且很简单。但是,它最适用于小集,因为它复制了整个集。
对于小型集合,我通常会创建类似这样的解析器/转换器方法
def convertSetToList(setName):
return list(setName)
然后我可以使用新的列表和访问索引号
userFields = convertSetToList(user)
name = request.json[userFields[0]]
作为一个列表,您将拥有所有其他可能需要使用的方法
我想知道这些函数对于不同的集合会有怎样的表现,所以我做了一个基准测试:
from random import sample
def ForLoop(s):
for e in s:
break
return e
def IterNext(s):
return next(iter(s))
def ListIndex(s):
return list(s)[0]
def PopAdd(s):
e = s.pop()
s.add(e)
return e
def RandomSample(s):
return sample(s, 1)
def SetUnpacking(s):
e, *_ = s
return e
from simple_benchmark import benchmark
b = benchmark([ForLoop, IterNext, ListIndex, PopAdd, RandomSample, SetUnpacking],
{2**i: set(range(2**i)) for i in range(1, 20)},
argument_name='set size',
function_aliases={first: 'First'})
b.plot()
这张图清楚地显示了一些方法(RandomSample, SetUnpacking和ListIndex)依赖于集合的大小,在一般情况下应该避免(至少在性能可能很重要的情况下)。正如其他答案所示,最快的方法是ForLoop。
然而,只要使用常数时间方法中的一种,性能差异就可以忽略不计。
iteration_utilities(免责声明:我是作者)包含了这个用例的方便函数:
>>> from iteration_utilities import first
>>> first({1,2,3,4})
1
我还将它包含在上面的基准测试中。它可以与其他两种“快速”解决方案竞争,但两者之间的差异并不大。