Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Python: Dev

itertools additions: one(), single_valued()

 

 

Python dev RSS feed   Index | Next | Previous | View Threaded


lists at informa

May 26, 2008, 8:29 AM

Post #1 of 6 (317 views)
Permalink
itertools additions: one(), single_valued()

Hi all,

I find the following two operations functions useful and general enough that I
would like to propose them for addition to itertools:

8< -------------------------------------------------------------------------
def single_valued(iterable):
it = iter(iterable)
try:
first_item = it.next()
except StopIteration:
raise ValueError, "empty iterable passed to 'single_valued()'"

for other_item in it:
if other_item != first_item:
raise ValueError, "non-single-valued iterable'"

return first_item
8< -------------------------------------------------------------------------

This first one embodies the assertion that all values of the iterable are
identical. If they are, that value is returned. Otherwise, an exception is
thrown. Maybe this should be rephrased such that the assertion part is
evaluated via an actual "assert", thereby turning it off in optimized mode.

Example use case: You get a list of lists, and expect each to be the same
length. Typical treatment:

list_len = len(lists[0])

New treatment:

list_len = single_valued(len(l) for l in lists)

Added benefits: The assumption is verified and clearly visible from the
source. "lists" may now be an iterable.

8< -------------------------------------------------------------------------
def one(iterable):
it = iter(iterable)
try:
v = it.next()
except StopIteration:
raise ValueError, "empty iterable passed to 'one()'"

try:
v2 = it.next()
raise ValueError, "iterable with more than one entry passed
to 'one()'"
except StopIteration:
return v
8< -------------------------------------------------------------------------

This one is a blatant rip-off from SQLAlchemy. It basically allows most
searches to be written using generator expressions:

what_i_am_looking_for = one(item for item in items if predicate(item))

This also encodes and checks the assumption that the sought item is unique
within the list of candidates. Again, the assertion part could be turned off
in optimized mode.

Opinions?

Andreas
Attachments: signature.asc (0.18 KB)


bborcic at gmail

May 26, 2008, 10:47 AM

Post #2 of 6 (300 views)
Permalink
Re: itertools additions: one(), single_valued() [In reply to]

> Opinions?
>
> Andreas

my_target, = iterable
my_target, = set(iterable)

quite readably does it, imho, or else one can use

[my_target] = iterable
[my_target] = set(iterable)

the error messages seem also OK.

Cheers, BB






_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


python at rcn

May 26, 2008, 12:27 PM

Post #3 of 6 (291 views)
Permalink
Re: itertools additions: one(), single_valued() [In reply to]

[Andreas]
> I find the following two operations functions useful and general
> enough that I would like to propose them for addition to itertools:

No thanks. Variants can already be constructed from existing tools.
And, they seem a little to specific to a data model where the first entry
has some special significance depending on whether or not it is unique.

> it = iter(iterable)
> try:
> first_item = it.next()
> except StopIteration:
> raise ValueError, "empty iterable passed to 'single_valued()'"
> for other_item in it:
> if other_item != first_item:
> raise ValueError, "non-single-valued iterable'"
> return first_item

This looks like a set() operation with a couple odd special cases for exceptions.

[] --> ValueError
If [x] --> x
[x x x] --> x
[x x y x] --> ValueError

The two non-exception cases both run the input iterable to exhaustion
and as such do not fit it with the lazy-evaluation theme of the itertools module.

> def one(iterable):
> it = iter(iterable)
> try:
> v = it.next()
> except StopIteration:
> raise ValueError, "empty iterable passed to 'one()'"
> try:
> v2 = it.next()
> raise ValueError, "iterable with more than one entry passed to 'one()'"
> except StopIteration:
> return v

Looks similar to list(islice(iterable,2)) followed by regular list-like handling.


> what_i_am_looking_for = one(item for item in items if predicate(item))

Looks similar to: wialf = ifilter(pred, items).next()


> This also encodes and checks the assumption that the sought item is unique
> within the list of candidates. Again, the assertion part could be turned off
> in optimized mode.

That is an odd assumption given that you're searching for a predicate
match and not a single item match. Also, it is often a better design
to enforce uniqueness constraints upon insertion, not upon lookup.


Raymond
_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


armin.ronacher at active-4

May 26, 2008, 12:40 PM

Post #4 of 6 (290 views)
Permalink
Re: itertools additions: one(), single_valued() [In reply to]

Hi,

Andreas Klöckner <lists <at> informa.tiker.net> writes:

> list_len = single_valued(len(l) for l in lists)
length, = set(map(len, lists))

> what_i_am_looking_for = one(item for item in items if predicate(item))
Is that really such a common case? In Python 2.6 you can use next for the same
thing however without the check if there is just one item:

what_i_am_looking_for = next(filter(predicate, items))

What I would like to see is a batch function defined like that:

def batch(iterable, n):
return izip(*repeat(iter(iterable), n))

It's a common pattern I use it very often.

Regards,
Armin

_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com


lists at informa

May 26, 2008, 2:18 PM

Post #5 of 6 (292 views)
Permalink
Re: itertools additions: one(), single_valued() [In reply to]

On Montag 26 Mai 2008, Boris Borcic wrote:
> > Opinions?
> >
> > Andreas
>
> my_target, = iterable
> my_target, = set(iterable)
>
> quite readably does it, imho, or else one can use
>
> [my_target] = iterable
> [my_target] = set(iterable)
>
> the error messages seem also OK.

True, thanks for pointing this out. :)

I guess the only places where my functions are useful are

a) if you don't want the intermediate result in a variable
or
b) if you can't stomach the storage for the set.

Andreas
Attachments: signature.asc (0.18 KB)


bborcic at gmail

May 27, 2008, 3:13 AM

Post #6 of 6 (275 views)
Permalink
Re: itertools additions: one(), single_valued() [In reply to]

Andreas Klöckner wrote:
> On Montag 26 Mai 2008, Boris Borcic wrote:
(...)
>>
>> [my_target] = iterable
>> [my_target] = set(iterable)
>>
>> the error messages seem also OK.
>
> True, thanks for pointing this out. :)
>
> I guess the only places where my functions are useful are
>
> a) if you don't want the intermediate result in a variable

On the near side to ugly, one could attempt the expression equivalents:

(lambda x:x)(*iterable)
(lambda x:x)(*set(iterable))

> or
> b) if you can't stomach the storage for the set.

Yeah, I guess it deserves study.

Cheers, BB

_______________________________________________
Python-Dev mailing list
Python-Dev [at] python
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/list-python-dev%40lists.gossamer-threads.com

Python dev RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.