如何从python中的单成员集中提取成员?


77

我最近遇到了一个场景,如果一个集合只包含一个元素,我想对该元素做些事情。为了获得元素,我决定采用以下方法:

element = list(myset)[0]

但这不是很令人满意,因为它创建了不必要的列表。也可以通过迭代来完成,但是迭代似乎也不自然,因为只有一个元素。我是否缺少简单的东西?

Answers:


102

元组拆包工作。

(element,) = myset

(顺便说一句,python-dev进行了探索,但拒绝添加myset.get()来从集合中返回任意元素。这里的讨论是Guido van Rossum回答12。

对于获得任意元素,我个人最喜欢的是(当您有一个未知数时,但是如果您只有一个也可以):

element = next(iter(myset)) ¹

1:在Python 2.5及更低版本中,您必须使用iter(myset).next()


9
非常好!我想,如果元件的数量不是1失败
劳伦斯·贡萨尔维斯

7
或者,如果您要假装Python拥有适合该工作的运算符(您的同事会讨厌您):element ,= myset
rdb 2014年

2
建议的改进:强调第一个对于非单一集合将失败。
Ioannis Filippidis 2014年

3
我不太喜欢那个逗号来告诉python这是一个元组。怎么样[element] = myset
Ant6n

5
next(iter(myset))表达式的优点是无需特殊分配即可使用,因此您可以将其作为参数传递给函数。
LarsH '16

26

在制作元组和制作迭代器之间,这几乎是一次洗礼,但迭代会赢得成功……:

$ python2.6 -mtimeit -s'x=set([1])' 'a=tuple(x)[0]'
1000000 loops, best of 3: 0.465 usec per loop
$ python2.6 -mtimeit -s'x=set([1])' 'a=tuple(x)[0]'
1000000 loops, best of 3: 0.465 usec per loop
$ python2.6 -mtimeit -s'x=set([1])' 'a=next(iter(x))'
1000000 loops, best of 3: 0.456 usec per loop
$ python2.6 -mtimeit -s'x=set([1])' 'a=next(iter(x))'
1000000 loops, best of 3: 0.456 usec per loop

不确定为什么所有答案都使用旧语法iter(x).next()而不是新语法next(iter(x)),这对我来说似乎更可取(并且在Python 3.1中也可以使用)。

但是,拆箱可以胜任以下两项工作:

$ python2.6 -mtimeit -s'x=set([1])' 'a,=x'
10000000 loops, best of 3: 0.174 usec per loop
$ python2.6 -mtimeit -s'x=set([1])' 'a,=x'
10000000 loops, best of 3: 0.174 usec per loop

当然,这是针对单项集的(如其他人所提到的,后者的优点是,如果您“知道”的集实际上只有一个项有多个,则失败很快)。对于具有任意N> 1项的集合,元组会变慢,迭代器不会:

$ python2.6 -mtimeit -s'x=set(range(99))' 'a=next(iter(x))'
1000000 loops, best of 3: 0.417 usec per loop
$ python2.6 -mtimeit -s'x=set(range(99))' 'a=tuple(x)[0]'
100000 loops, best of 3: 3.12 usec per loop

因此,对于单例和next(iter(x))一般情况,打开包装似乎是最好的。


为什么使用Python2.x语法?我只在那里进行真正的编程,并且python系统上是Python 2.5,因此当我按键盘绑定打开python控制台时会出现什么情况。
u0b34a0f6ae

2.6非常适合用于“实际编程”,并且比2.5更丰富;坚持使用2.5的唯一原因是您的外部环境是否对您造成限制(App Engine,Civilization 4等)。next(x)和x.next()都在2.6中工作,但是next(x)更好(让您指定默认值而不是捕获StopIteration异常,需要少一个字符;-)。
Alex Martelli,2009年

@Alex:无需说服我,我宁愿使用python 2.6。我使用的是debian,debian尚未完成向Python 2.6的过渡!(Pyhthon 2.6本身可用,但没有发行的第3部分库。)
u0b34a0f6ae 2009年

但是由于您提到next(..)了Python 2.6中提供的功能,因此我现在更好地理解了您的观点!那是好消息。
u0b34a0f6ae

@ kaizer.se,是的-同样,正如我提到的,App Engine也是2.5,而Civilization IV(其他可编写脚本的游戏和应用可能会更落后),Mac OSX 10.5(如果您要分发使用系统Python而不是捆绑自己的系统),尽管10.6最终确实使用了Python 2.6,依此类推-可能有很多这样的环境限制,迫使使用2.5(甚至更早的版本);但是是的,2.6在可用时很吸引人(下一个内置功能只是一个花哨,而又多汁;-)。
Alex Martelli,2009年

20

我认为kaizer.se的答案很好。但是,如果您的集合可能包含多个元素,并且您想要一个不太随意的元素,则可能要使用minmax。例如:

element = min(myset)

要么:

element = max(myset)

(请勿使用sorted,因为这种用法会产生不必要的开销。)


这家伙 如果集合是单例,则其中的孤立元素应该是其最小值和最大值。多谢兄弟。
塞缪尔·恩德

10

我建议:

element = myset.pop()

3
在某些情况下,这可能会起作用,但是会改变集合。
递归

@recursive怎么样element = myset.copy().pop()
stevepastelan's

@recursive,但是如果是单项设置,突变是否重要?
阿斯特丽德

1
@Astrid:对于某些用例,是的。对于其他人,不。
递归

2

您可以使用element = tuple(myset)[0]效率更高的方法,也可以执行以下操作

element = iter(myset).next()

我猜构造一个迭代器比构造一个元组/列表更有效。


1
为什么您认为构造迭代器效率更高?
克雷格·麦昆

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.