从集合中选择单个项:Python

从集合中选择单个项:Python,python,iterator,generator,Python,Iterator,Generator,我创建了一个实用函数,从生成器表达式返回预期的单个项 print one(name for name in ('bob','fred') if name=='bob') 这是个好办法吗 def one(g): try: val = g.next() try: g.next() except StopIteration: return val else:

我创建了一个实用函数,从生成器表达式返回预期的单个项

print one(name for name in ('bob','fred') if name=='bob')
这是个好办法吗

def one(g):
    try:
        val = g.next()
        try:
            g.next()
        except StopIteration:
            return val
        else:
            raise Exception('Too many values')
    except StopIteration:
        raise Exception('No values')
简单方法:

print (name for name in ('bob', 'fred') if name == 'bob').next()
如果您确实希望在存在多个值时出错,则需要一个函数。我能想到的最简单的方法是(编辑也可以使用列表):

看看这个方法

>i2=itertools.islice((如果name='bob','fred')中的name的名称为'bob',0,1,1)
>>>i2.下一步()
“鲍勃”
>>>i2.下一步()
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
停止迭代
>>> 
本模块实现了许多迭代器构建块,其灵感来自Haskell和SML编程语言的构造。每一个都以适合Python的形式进行了重铸

该模块标准化了一组核心的快速、高效内存工具,这些工具本身或组合使用都很有用。标准化有助于避免可读性和可靠性问题,当许多不同的人创建自己略有不同的实现时,会出现这些问题,每个实现都有自己的怪癖和命名约定

这些工具被设计成可以很容易地相互结合。这使得在纯Python中简洁高效地构造更专门的工具变得容易

你是说

def one( someGenerator ):
    if len(list(someGenerator)) != 1: raise Exception( "Not a Singleton" )

你想用这些额外的代码实现什么

下面是我对
one()
函数的尝试。我将避免显式的
.next()
调用,而是使用for循环

def one(seq):
    counter = 0
    for elem in seq:
        result = elem
        counter += 1
        if counter > 1:
            break
    if counter == 0:
        raise Exception('No values')
    elif counter > 1:
        raise Exception('Too many values')
    return result
首先,(回答实际问题!)您的解决方案将与其他建议的变体一样工作良好

我要补充的是,在这种情况下,国际海事组织,发电机过于复杂。如果您希望有一个值,那么您可能永远不会有足够的内存使用成为一个问题,因此我只会使用明显且更清晰的:

children = [name for name in ('bob','fred') if name=='bob']
if len(children) == 0:
    raise Exception('No values')
elif len(children) > 1:
    raise Exception('Too many values')
else:
    child = children[0]

一个更简单的解决方案是使用元组解包。这将完成您想要的所有操作,包括检查它是否只包含一项

单项:

 >>> name, = (name for name in ('bob','fred') if name=='bob')
 >>> name
 'bob'
项目太多:

>>> name, = (name for name in ('bob','bob') if name=='bob')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack
>>name,=(如果name='bob','bob')中的name的名称为name)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
ValueError:要解压缩的值太多
无项目:

>>> name, = (name for name in ('fred','joe') if name=='bob')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: need more than 0 values to unpack
>>name,=(如果name='bob',则在('fred','joe')中为name命名)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
ValueError:需要0个以上的值才能解包

如何使用Python的for。。用一个计数器?类似于未知的答案

def one(items):
    count = 0
    value = None

    for item in items:
        if count:
            raise Exception('Too many values')

        count += 1
        value = item

    if not count:
        raise Exception('No values')

    return value

对于使用或对第三方库感兴趣的用户,使用本机错误处理实现此类工具:

> pip install more_itertools
代码

import more_itertools as mit


mit.one(name for name in ("bob", "fred") if name == "bob")
# 'bob'

mit.one(name for name in ("bob", "fred", "bob") if name == "bob")
# ValueError: ...

mit.one(name for name in () if name == "bob")
# ValueError: ...

有关详细信息,请参阅。与接受的答案类似。

TypeError:类型为“generator”的对象没有len()。我想我可以:len(list(someGenerator))这就是我要做的,它看起来更清晰,对性能的影响应该最小。因为生成器不应该是无限的,所以这似乎是解决这个不公平想法的最优雅的解决方案。@hop生成器可以是无限的。我曾经写过一个CPU利用率百分比生成器。不管怎样,只使用一个元素来读取整个生成的列表是非常浪费的。为什么您关心是否有多个项?我正在处理关系数据库中的数据。我想在处理的同时检查其完整性,完整性规则可以是“父级必须只有一个特定类型的子级”,或者“父级必须有一个且只有一个特定类型的子级”,这听起来像是一个非常糟糕的主意(tm)。我是认真的!产生g的东西应该检查一致性,而不是消耗g的东西。如果我问one()要一个g,它会回答“对不起,我可以给你一个,但我不会,因为我有太多了!”我会诅咒[你,可能吧]。请接受在我使用它的条件下这是完全有效的,以后请坚持回答特定的问题,不要试图让人发火。聪明,但可能太聪明了。还有,很容易错过。我更喜欢写
[name]=(如果name='bob','fred'),那么name for name in('bob','fred'))
–编译时完全相同,但更明显的是发生了一些事情。这个答案很好,因为它可以很容易地进行调整,以有效地执行类似的关键操作,如SingleOrDefault,而单线技巧虽然很酷,但却无法做到这一点。
> pip install more_itertools
import more_itertools as mit


mit.one(name for name in ("bob", "fred") if name == "bob")
# 'bob'

mit.one(name for name in ("bob", "fred", "bob") if name == "bob")
# ValueError: ...

mit.one(name for name in () if name == "bob")
# ValueError: ...