如何从集合中检索一个元素而不将其删除?

663

假设如下:

>>> s = set([1, 2, 3])

如何在不使用 s.pop() 的情况下从 s 中获取一个值(任意值)?我想在确认可以将其删除之前保留集合中的项目 - 这只有在对另一个主机进行异步调用后才能确定。

简单粗暴:

>>> elem = s.pop()
>>> s.add(elem)

你知道更好的方法吗?最好是常数时间。


36
有人知道为什么Python还没有实现这个函数吗? - hlin117
6
使用场景是什么?集合之所以没有这种能力是有原因的。您应该通过迭代它并执行类似于“union”等的集合操作,而不是从中获取元素。例如,next(iter({3,2,1}))总是返回1,因此如果您认为它会返回随机元素-它不会。那么也许您只是使用了错误的数据结构?使用场景是什么? - user1685095
1
@hlin117 因为集合是一种无序集合。由于不需要顺序,因此在给定位置检索元素是没有意义的 - 预计它是随机的。 - Jeyekomon
1
@hlin117 那么为什么这没有意义呢?它被称为“有放回抽样”... - Radio Controlled
4
一个我经常遇到的合理应用场景是这样的:我正在编写一项测试,并且获得了一个集合。我想查看其中任何一个值以便为测试构建更多数据。我不关心我得到哪一个值,我也不在乎每次是否相同或不同。我只需要从集合中获取一个值。 - Troy Daniels
显示剩余7条评论
15个回答

3

对于小的集合,我通常会创建一种解析器/转换器方法,类似于以下内容:

def convertSetToList(setName):
return list(setName)

然后我可以使用新列表并通过索引号进行访问。
userFields = convertSetToList(user)
name = request.json[userFields[0]]

作为列表,您将拥有所有其他可能需要使用的方法。

10
为什么不直接使用list而要创建一个转换方法? - Daren Thomas

2
您可以解包值以访问元素:
s = set([1, 2, 3])

v1, v2, v3 = s

print(v1,v2,v3)
#1 2 3

我想你可以解包成 v1, _*。没有通配符,您需要精确匹配元素数量。但正如前面的答案 https://dev59.com/1HVD5IYBdhLWcg3wL4cA#45803038 中所指出的那样,这会很慢。 - MSalters

0
如果你只想要第一个元素,可以尝试这样做: b = (a-set()).pop()

1
Set是一个无序集合,因此不存在“第一个元素”这样的概念 :) - piit79

-3

尝试一下 s.copy().pop() 怎么样?我没有计时,但它应该可以工作,而且很简单。然而,它最适合小集合,因为它会复制整个集合。


-8

另一个选项是使用带有您不关心的值的字典。例如:


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(在set之前)保持向后兼容。这可能不是最好的答案,但这是另一种选择。
编辑:你甚至可以像这样做一些事情,隐藏你使用了字典而不是数组或集合的事实。

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()

3
这并不像你希望的那样起作用。在 Python2 中,keys() 是一个 O(n) 的操作,因此你不再是常数时间,但至少 keys[0] 会返回你期望的值。在 Python3 中,keys() 是一个 O(1) 操作,太棒了!然而,它不再返回一个列表对象,而是返回一个类似 set 的对象,不能进行索引,所以 keys[0] 会抛出 TypeError。https://dev59.com/01kS5IYBdhLWcg3w-Kzl - sage88

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接