假设如下:

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

我如何获得一个值(任何值)的 s 没有做 s.pop()?我想离开该项目设置直到我确信,我可以移除它-我只能确定之后一个步呼叫另一个主机。

快速和肮脏的:

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

但是你知道一个更好的办法?理想的情况在不断的时间。

有帮助吗?

解决方案

两种选择不需要复制一整套:

for e in s:
    break
# e is now an element from s

或者...

e = next(iter(s))

但在一般情况下,集不支持索引或切片。

其他提示

少代码是:

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

显然这将会创建一个新的名单,其中包含每一个部件的设置,所以不是很大的,如果你的设定是非常大的。

提供一些时间的数字背后的不同方法,考虑以下代码。Get()为我定制的外向Python setobject.c仅仅是一个pop()而不删除要件。

from timeit import *

stats = ["for i in xrange(1000): iter(s).next()   ",
         "for i in xrange(1000): \n\tfor x in s: \n\t\tbreak",
         "for i in xrange(1000): s.add(s.pop())   ",
         "for i in xrange(1000): s.get()          "]

for stat in stats:
    t = Timer(stat, setup="s=set(range(100))")
    try:
        print "Time for %s:\t %f"%(stat, t.timeit(number=1000))
    except:
        t.print_exc()

输出为:

$ ./test_get.py
Time for for i in xrange(1000): iter(s).next()   :       0.433080
Time for for i in xrange(1000):
        for x in s:
                break:   0.148695
Time for for i in xrange(1000): s.add(s.pop())   :       0.317418
Time for for i in xrange(1000): s.get()          :       0.146673

这意味着 为打破 解决方案是最快的(有时候速度比定义获取()解决方案)。

tl博士

for first_item in muh_set: break 仍然是最佳办法Python3.x. 诅咒你,圭多。

y u做这个

欢迎来到还有另一组Python3.x计时,从外推 wr。's优秀 蟒蛇2.x具体的响应.不像 AChampion's也同样有用 蟒蛇3.x具体的响应, ,时间下面 时间异常的解决方案的上述建议–其中包括:

代码段伟大的喜悦

打开,调整、时间:

from timeit import Timer

stats = [
    "for i in range(1000): \n\tfor x in s: \n\t\tbreak",
    "for i in range(1000): next(iter(s))",
    "for i in range(1000): s.add(s.pop())",
    "for i in range(1000): list(s)[0]",
    "for i in range(1000): random.sample(s, 1)",
]

for stat in stats:
    t = Timer(stat, setup="import random\ns=set(range(100))")
    try:
        print("Time for %s:\t %f"%(stat, t.timeit(number=1000)))
    except:
        t.print_exc()

快废弃的永恒的时间

看哪! 下令由最快到最慢段:

$ ./test_get.py
Time for for i in range(1000): 
    for x in s: 
        break:   0.249871
Time for for i in range(1000): next(iter(s)):    0.526266
Time for for i in range(1000): s.add(s.pop()):   0.658832
Time for for i in range(1000): list(s)[0]:   4.117106
Time for for i in range(1000): random.sample(s, 1):  21.851104

Faceplants为整个家庭

毫不奇怪, 手册迭代,仍然是至少速度的两倍 作为下一个最快速的解决方案。虽然差距有所下降,从坏的老蟒蛇2.x天(在其手册的迭代是至少四倍),这令人失望的 PEP20 狂热者在我的最详细的解决方案是最好的。至少转换集成一个清单只是提取的第一个元件的设置是一样可怕的预期。 谢谢Guido,可能他的光继续指导我们。

令人惊讶的是, 丽贝卡基于解决方案是绝对可怕的。 列表转换是坏的,但是 random 真的 需要的可怕-酱饼。这么多的 随机数量的上帝.

我只是希望非晶,他们将鼓励的一个 set.get_first() 方法对于我们了。如果你正在读这个,他们:"请。做一些事情。"

因为你想要一个随机的元素,这也将工作:

>>> import random
>>> s = set([1,2,3])
>>> random.sample(s, 1)
[2]

该文件似乎并不提到的性能 random.sample.从一个真正快速的经验性测试与一个巨大的列表和一个巨大的集中,它似乎是恒定不变的时间表,但没有为设置。此外,迭代过一组并不是随机的;所以是不定的但是可以预见的:

>>> list(set(range(10))) == range(10)
True 

如果随机性是重要的,你需要一堆的要素在不断的时间(大集),我会使用 random.sample 并转换为一个列表中的第一:

>>> lst = list(s) # once, O(len(s))?
...
>>> e = random.sample(lst, 1)[0] # constant time

我想知道如何的功能将执行,用于不同的组,因此我做了一个基准:

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

enter image description here

这个情节清楚地表明,有些做法(RandomSample, SetUnpackingListIndex)取决于该小组应该避免在一般情况下(至少是如果性能 可能会 可重要)。如已经显示通过其他的答案最快的方法是 ForLoop.

然而,只要作为一个恒定时间的方法是使用性能差异可以忽略不计。


iteration_utilities (免责声明:我是作者)中包含一个便利功能,用于这种使用情况: first:

>>> from iteration_utilities import first
>>> first({1,2,3,4})
1

我也包含在基准之上。它可与其他两个"快速"的解决方案,但该差不多两种方式。

我用一个实用工具的功能,我写了。它的名字是有些误导,因为这种暗示这可能是一个随机项目或类似的东西。

def anyitem(iterable):
    try:
        return iter(iterable).next()
    except StopIteration:
        return None

看似的 最紧凑的 (6的符号)虽 非常慢 的方式来获得一个组件(由 PEP3132):

e,*_=s

与Python3.5+你也可以使用这个7符号表达的(由于 PEP448):

[*s][0]

这两个选项是大约1000倍慢我的机器比用于环的方法。

以下@wr。后,我得到了类似的结果(对Python3.5)

from timeit import *

stats = ["for i in range(1000): next(iter(s))",
         "for i in range(1000): \n\tfor x in s: \n\t\tbreak",
         "for i in range(1000): s.add(s.pop())"]

for stat in stats:
    t = Timer(stat, setup="s=set(range(100000))")
    try:
        print("Time for %s:\t %f"%(stat, t.timeit(number=1000)))
    except:
        t.print_exc()

输出:

Time for for i in range(1000): next(iter(s)):    0.205888
Time for for i in range(1000): 
    for x in s: 
        break:                                   0.083397
Time for for i in range(1000): s.add(s.pop()):   0.226570

然而,在改变基础设置(例如呼叫 remove())事情严重,可迭代的例子(for, iter):

from timeit import *

stats = ["while s:\n\ta = next(iter(s))\n\ts.remove(a)",
         "while s:\n\tfor x in s: break\n\ts.remove(x)",
         "while s:\n\tx=s.pop()\n\ts.add(x)\n\ts.remove(x)"]

for stat in stats:
    t = Timer(stat, setup="s=set(range(100000))")
    try:
        print("Time for %s:\t %f"%(stat, t.timeit(number=1000)))
    except:
        t.print_exc()

结果:

Time for while s:
    a = next(iter(s))
    s.remove(a):             2.938494
Time for while s:
    for x in s: break
    s.remove(x):             2.728367
Time for while s:
    x=s.pop()
    s.add(x)
    s.remove(x):             0.030272

怎么样 s.copy().pop()?我没有时它,但是它应该工作而且它是简单的。它最适合小组然而,因为它将整个集。

另一种选择是采用一个词典有价值你不关心。E.g.,


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]

一个副作用的这种选择是,你的代码将是向后兼容旧,预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()
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top