如何从集合中获取元素而不移除它?
假设有以下情况:
>>> s = set([1, 2, 3])
我想从 s
中获取一个值(任何值),但不想使用 s.pop()
。我希望这个值能留在集合里,直到我确认可以把它移除——而我只有在异步调用另一个主机后才能确认。
简单粗暴的方法:
>>> elem = s.pop()
>>> s.add(elem)
不过,你知道有没有更好的方法吗?理想情况下是常量时间的。
15 个回答
207
我想知道这些函数在不同数据集上的表现,所以我做了个性能测试:
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
(免责声明:我是这个库的作者)里面有一个方便的函数可以用在这种情况下:first
:
>>> from iteration_utilities import first
>>> first({1,2,3,4})
1
我也把它包含在上面的性能测试中。它可以和另外两个“快速”的解决方案相媲美,但无论如何,差别都不大。
213
最简单的代码如下:
>>> s = set([1, 2, 3])
>>> list(s)[0]
1
显然,这段代码会创建一个新列表,里面包含了集合中的每一个成员。如果你的集合很大,这样做就不太好了。
837
有两种方法可以做到这一点,而不需要复制整个集合:
for e in s:
break
# e is now an element from s
或者...
e = next(iter(s))
不过一般来说,集合是不支持索引或切片的。