假设如下:
>>> 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)
但你知道更好的办法吗?理想情况是在常数时间内。
当前回答
你可以解包这些值来访问元素:
s = set([1, 2, 3])
v1, v2, v3 = s
print(v1,v2,v3)
#1 2 3
其他回答
因为你想要一个随机元素,这也可以:
>>> import random
>>> s = set([1,2,3])
>>> random.sample(s, 1)
[2]
文档中似乎没有提到random.sample的性能。从一个非常快速的经验测试中,有一个巨大的列表和一个巨大的集合,对于列表来说似乎是常数时间,而对于集合来说则不是。而且,集合上的迭代不是随机的;顺序没有定义,但可以预测:
>>> list(set(range(10))) == range(10)
True
如果随机性很重要,并且你需要在常数时间内(大型集合)使用一堆元素,那么我会使用随机性。先采样并转换为列表:
>>> lst = list(s) # once, O(len(s))?
...
>>> e = random.sample(lst, 1)[0] # constant time
另一种选择是使用包含您不关心的值的字典。例如,
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版本。这可能不是最好的答案,但这是另一种选择。
编辑:你甚至可以这样做来隐藏你使用字典而不是数组或集合的事实:
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()
看似最紧凑(6个符号),但非常慢的方法来获得一个集合元素(由PEP 3132实现):
e,*_=s
使用Python 3.5+,你也可以使用这个7符号表达式(感谢PEP 448):
[*s][0]
在我的机器上,这两个选项都比for循环方法慢大约1000倍。
我想知道这些函数对于不同的集合会有怎样的表现,所以我做了一个基准测试:
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
我还将它包含在上面的基准测试中。它可以与其他两种“快速”解决方案竞争,但两者之间的差异并不大。
对于小型集合,我通常会创建类似这样的解析器/转换器方法
def convertSetToList(setName):
return list(setName)
然后我可以使用新的列表和访问索引号
userFields = convertSetToList(user)
name = request.json[userFields[0]]
作为一个列表,您将拥有所有其他可能需要使用的方法