Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

select single item from a collection : Python

I created a utility function to return the expected single item from an generator expression

print one(name for name in ('bob','fred') if name=='bob')

Is this a good way to go about it?

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')
like image 789
GHZ Avatar asked Jan 23 '09 11:01

GHZ


2 Answers

A simpler solution is to use tuple unpacking. This will already do everything you want, including checking that it contains exactly one item.

Single item:

 >>> name, = (name for name in ('bob','fred') if name=='bob')
 >>> name
 'bob'

Too many items:

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

No items:

>>> 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
like image 114
Brian Avatar answered Oct 03 '22 18:10

Brian


For those using or interested in a third-party library, more_itertools implements such a tool with native error handling:

> pip install more_itertools

Code

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: ...

See more_itertools docs for details. The underlying source code is similar to the accepted answer.

like image 26
pylang Avatar answered Oct 03 '22 18:10

pylang