如何从单元素集合中提取成员?
我最近遇到了一个情况,就是当一个集合里只有一个元素时,我想对这个元素做点什么。为了获取这个元素,我采用了这个方法:
element = list(myset)[0]
不过这样做让我觉得不太满意,因为它创建了一个不必要的列表。其实也可以用循环来做,但用循环似乎也不太自然,因为里面只有一个元素。我是不是漏掉了什么简单的方法呢?
8 个回答
我觉得kaizer.se的回答非常不错。不过,如果你的集合可能包含多个元素,而你想要一个不那么随意的元素,那么你可以考虑使用min
或者max
。比如:
element = min(myset)
或者:
element = max(myset)
(不要使用sorted
,因为这样做会增加不必要的开销。)
在创建元组和创建迭代器之间,差不多是一样的,但迭代器稍微胜出一点……:
$ 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
当然,这里说的是单个元素的集合(就像其他人提到的,后者的好处是如果你“知道”的集合其实有多个元素,它会很快报错)。对于包含多个元素的集合,元组的速度会变慢,而迭代器则不会:
$ 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))
似乎是最合适的。
元组解包是有效的,它验证了一个假设:这个 set
里 恰好 有一个元素(如果元素太多或太少,就会抛出 ValueError
错误)。
(element,) = myset
# Or equivalently, without requiring trailing comma:
[element] = myset
顺便提一下,python-dev 曾经探讨过但最终拒绝了添加 myset.get()
这个功能,以便从集合中返回一个任意元素。讨论在这里,Guido van Rossum 的回答可以看1 和 2。
我个人最喜欢获取任意元素的方法是(当你不知道元素数量时也适用,如果只有一个元素也可以):
element = next(iter(myset)) ¹
1: 在 Python 2.5 及之前的版本中,你需要使用 iter(myset).next()