Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Can this be written more concisely in a functional style

0 views
Skip to first unread message

MetalOne

unread,
Nov 17, 2003, 7:48:36 PM11/17/03
to
1)
def f(xs):
for x in xs:
if test(x): return True
return False

I know that I can do (2), but it operates on the whole list and the original
may break out early. I want the efficiency of (1), but the conciseness of (2).

2)
return True in map(test,xs)

Ben Finney

unread,
Nov 17, 2003, 7:38:09 PM11/17/03
to
On 17 Nov 2003 16:48:36 -0800, MetalOne wrote:
> 1)
> def f(xs):
> for x in xs:
> if test(x): return True
> return False

Makes it obvious that there is a way for the iternation to end early.

> 2)
> return True in map(test,xs)

Strongly implies ("foo in list", "map()") that the entire list will be
iterated. Any other behaviour would be unexpected to the person reading
the code.

> I know that I can do (2), but it operates on the whole list and the
> original may break out early. I want the efficiency of (1), but the
> conciseness of (2).

I think that in seeking to make it more concise, you're also seeking to
make it less obvious. Anything that has the semantics of "loop over the
whole list" in a single statement, isn't going to help people understand
that a common case is for the iteration to end early. Which is probably
a good reason for it not to appear.

If you want to hide the algorithm, do so inside a helper function. Then
you have consision in the places where you're actually using it, and
explicit semantics where the algorithm is implemented.

--
\ "A cynic is a man who, when he smells flowers, looks around for |
`\ a coffin." -- Henry L. Mencken |
_o__) |
Ben Finney <http://bignose.squidly.org/>

Ben Finney

unread,
Nov 17, 2003, 7:39:33 PM11/17/03
to
On 18 Nov 2003 11:28:09 +1050, Ben Finney wrote:
> On 17 Nov 2003 16:48:36 -0800, MetalOne wrote:
>> def f(xs):
>> for x in xs:
>> if test(x): return True
>> return False
>
> If you want to hide the algorithm, do so inside a helper function.
> Then you have consision in the places where you're actually using it,
> and explicit semantics where the algorithm is implemented.

On second look, you appear to *be* putting this in a helper function,
presumably for the purpose of hiding the implementation. If so, it's a
good thing that the implementation is explicit here -- anyone who goes
looking into this function wants it obvious how it works.

--
\ "When I get real bored, I like to drive downtown and get a |
`\ great parking spot, then sit in my car and count how many |
_o__) people ask me if I'm leaving." -- Steven Wright |
Ben Finney <http://bignose.squidly.org/>

Bengt Richter

unread,
Nov 17, 2003, 8:55:46 PM11/17/03
to

That's not quite the same, unless you guarantee that test(x)==bool(test(x))==True when
test(x) is logically true, and never returns True otherwise. (E.g., what if test were
def test(x): return x ? f(range(5)) will give you a True when you hit 1 but, map(test,range(5))
will just be the numbers, and there will be no True in that).

I guess with generator expressions you will soon be able to write

def f(xs): return True in (bool(test(x)) for x in xs)

We can fake the generator expression and a test that will show us how far it went, to see...

>>> def test(x): print x; return x=='3'
...
(Ok, that does guarantee a bool, but some other test might conceivably not).

>>> def gx(fun, seq):
... for x in seq: yield bool(fun(x))
...
>>> xs = 'abc123def456'

and

>>> def f(xs): return True in gx(test, xs)
...
>>> f(xs)
a
b
c
1
2
3
True

Regards,
Bengt Richter

Georgy Pruss

unread,
Nov 18, 2003, 2:11:56 AM11/18/03
to
Something like
return any( test, xs )
or
return xs.any( test )
?

--
Georgy Pruss
E^mail: 'ZDAwMTEyMHQwMzMwQGhvdG1haWwuY29t\n'.decode('base64')


"MetalOne" <j...@iteris.com> wrote in message news:92c59a2c.03111...@posting.google.com...

MetalOne

unread,
Nov 18, 2003, 2:40:03 AM11/18/03
to
Maybe my post was not clear.
I want a means to test if there exists an element in the list that
satisfies a predicate.

Actually, when I word it that way, I guess what I want is PEP 289,
universal and existential qualifiers.

I guess I'll have to wait.

Alex Martelli

unread,
Nov 18, 2003, 3:35:23 AM11/18/03
to
MetalOne wrote:

[2] is quite different [1] in terms of semantics, of course. [1] will
accept any true (non-false) result, such as 23 or 'foo', [2] won't. If
[2]'s semantics are what you want,

return True in itertools.imap(test, xs)

should give you exactly what you require. Otherwise, you may want to
ensure a 'bool' is further applied, either by using a lambda or by
nesting two imap calls.


Alex

Jeremy Fincher

unread,
Nov 18, 2003, 5:59:47 AM11/18/03
to
j...@iteris.com (MetalOne) wrote in message news:<92c59a2c.03111...@posting.google.com>...

> Maybe my post was not clear.
> I want a means to test if there exists an element in the list that
> satisfies a predicate.

Sure there is. The code that you showed was an excellent way to do
so.

> Actually, when I word it that way, I guess what I want is PEP 289,
> universal and existential qualifiers.
>
> I guess I'll have to wait.

Why? Why not just stuff the code you wrote into an appropriately
named function and use that?

Anyway, here are more efficient implementations:

def any(p, seq):
"""Returns true if any element in seq satisfies predicate p."""
for elt in itertools.ifilter(p, seq):
return True
else:
return False

def all(p, seq):
"""Returns true if all elements in seq satisfy predicate p."""
for elt in itertools.ifilterfalse(p, seq):
return False
else:
return True

Jeremy

Michele Simionato

unread,
Nov 18, 2003, 8:02:21 AM11/18/03
to
j...@iteris.com (MetalOne) wrote in message news:<92c59a2c.0311171648.
> return True in map(test,xs)

return True in itertools.imap(test,xs) ?

M.

Michele Simionato

unread,
Nov 18, 2003, 10:14:45 AM11/18/03
to
tweed...@hotmail.com (Jeremy Fincher) wrote in message news:<698f09f8.0311...@posting.google.com>...

> Anyway, here are more efficient implementations:
>
> def any(p, seq):
> """Returns true if any element in seq satisfies predicate p."""
> for elt in itertools.ifilter(p, seq):
> return True
> else:
> return False
>
> def all(p, seq):
> """Returns true if all elements in seq satisfy predicate p."""
> for elt in itertools.ifilterfalse(p, seq):
> return False
> else:
> return True
>
> Jeremy

This is a perfect example of why I dislike the "else" clause. I
would code this as

def any(p, seq):
"""Returns true if any element in seq satisfies predicate p."""
for elt in itertools.ifilter(p, seq):
return True

return False

def all(p, seq):
"""Returns true if all elements in seq satisfy predicate p."""
for elt in itertools.ifilterfalse(p, seq):
return False

return True

Since the "else" is unnecessary, it disturbs me, I get confused,
I don't see why it is used (there is no break in the loop) and the
code becomes much harder to read, for me. OTOH I am sure 99% of
people would say "look, it is obvious, if elt is in the output
of ifilter it will return True, else False (viceversa in the
second case)". But may brain sees that the "else" is unncessary
and immediately it is disturbed by th redundance.
Am I the only one? ;)

Michele

Alexander Schmolck

unread,
Nov 18, 2003, 12:39:22 PM11/18/03
to
mi...@pitt.edu (Michele Simionato) writes:

> Am I the only one? ;)

I think such code is likely to fool people into thinking that the else part of
loops is only executed if no single iteration takes place.

'as

Alexander Schmolck

unread,
Nov 18, 2003, 12:37:15 PM11/18/03
to
Dennis Lee Bieber <wlf...@ix.netcom.com> writes:

> > def all(p, seq):
> > """Returns true if all elements in seq satisfy predicate p."""
> > for elt in itertools.ifilterfalse(p, seq):
> > return False
> > return True
> >

> I'd be wasting a local with
>
> def any(p, seq):
> """ibid"""
> a = False


> for elt in itertools.ifilter(p, seq):

> a = True
break
> return a

You're not just wasting a local.

'as

Alexander Schmolck

unread,
Nov 18, 2003, 12:48:34 PM11/18/03
to
tweed...@hotmail.com (Jeremy Fincher) writes:

> j...@iteris.com (MetalOne) wrote in message news:<92c59a2c.03111...@posting.google.com>...
> > Maybe my post was not clear.
> > I want a means to test if there exists an element in the list that
> > satisfies a predicate.
>
> Sure there is. The code that you showed was an excellent way to do
> so.
>
> > Actually, when I word it that way, I guess what I want is PEP 289,
> > universal and existential qualifiers.
> >
> > I guess I'll have to wait.
>
> Why? Why not just stuff the code you wrote into an appropriately
> named function and use that?
>
> Anyway, here are more efficient implementations:
>
> def any(p, seq):
> """Returns true if any element in seq satisfies predicate p."""
> for elt in itertools.ifilter(p, seq):
> return True
> else:
> return False

Another alternative (also works for python2.2, but is likely to be slower):

def some(predicate, *seqs):
iterables = map(iter, seqs)
try:
while 1:
boo = predicate(*[iterable.next() for iterable in iterables])
if boo: return boo
except StopIteration: return False

'as

Anton Vredegoor

unread,
Nov 18, 2003, 1:03:12 PM11/18/03
to
mi...@pitt.edu (Michele Simionato) wrote:

>def any(p, seq):
> """Returns true if any element in seq satisfies predicate p."""
> for elt in itertools.ifilter(p, seq):
> return True
> return False
>
>def all(p, seq):
> """Returns true if all elements in seq satisfy predicate p."""
> for elt in itertools.ifilterfalse(p, seq):
> return False
> return True
>
>Since the "else" is unnecessary, it disturbs me, I get confused,
>I don't see why it is used (there is no break in the loop) and the
>code becomes much harder to read, for me. OTOH I am sure 99% of
>people would say "look, it is obvious, if elt is in the output
>of ifilter it will return True, else False (viceversa in the
>second case)". But may brain sees that the "else" is unncessary
>and immediately it is disturbed by th redundance.
>Am I the only one? ;)

Well, don't the multiple returns disturb you? I'd suggest this but
probably it's too clever:

from itertools import islice,ifilter

def any(predicate,seq):
return bool(list(islice(ifilter(predicate,seq),1)))

def test():
xs = 'abc123def456'
def fun(x):
print x
return x == '3'
print any(fun,xs)

if __name__=='__main__':
test()

Anton


MetalOne

unread,
Nov 18, 2003, 1:52:58 PM11/18/03
to
My intention was that test() return True or False.
So True in itertools.imap(test, xs) is what I was looking for.

I also like the any() function suggested above.


def any(p, seq):
"""Returns true if any element in seq satisfies predicate p."""
for elt in itertools.ifilter(p, seq):
return True
return False


In the itertools.imap version does
<True in> test against a continually growing list, ie.
True in [False]
True in [False, False]
True in [False, False, False]
True in [False, False, False, True]

or does it just apply <in> to the next generated element.

Is the itertools.imap version as efficient as the for loop version?


Thanks.

Jeremy Fincher

unread,
Nov 18, 2003, 4:04:33 PM11/18/03
to
mi...@pitt.edu (Michele Simionato) wrote in message news:<2259b0e2.03111...@posting.google.com>...

> tweed...@hotmail.com (Jeremy Fincher) wrote in message news:<698f09f8.0311...@posting.google.com>...
> > def any(p, seq):
> > """Returns true if any element in seq satisfies predicate p."""
> > for elt in itertools.ifilter(p, seq):
> > return True
> > else:
> > return False
> >
> > def all(p, seq):
> > """Returns true if all elements in seq satisfy predicate p."""
> > for elt in itertools.ifilterfalse(p, seq):
> > return False
> > else:
> > return True
>
> This is a perfect example of why I dislike the "else" clause. I
> would code this as
>
> def any(p, seq):
> """Returns true if any element in seq satisfies predicate p."""
> for elt in itertools.ifilter(p, seq):
> return True
> return False
>
> def all(p, seq):
> """Returns true if all elements in seq satisfy predicate p."""
> for elt in itertools.ifilterfalse(p, seq):
> return False
> return True
>
> Since the "else" is unnecessary, it disturbs me, I get confused,
> I don't see why it is used (there is no break in the loop)

It's used because the for loop is effectively serving as an if
statement. Iterators have no __nonzero__ method -- you can't simply
bool() them. So I use a for loop like a if statement, and throw the
else in there to emphasize that usage. The for loop will never
iterate; either its body executes or it doesn't.

An alternative way to code this would be:

def any(p, seq):
try:
itertools.ifilter(p, seq).next()
return True
except StopIteration:
return False

but I find that less clear.

I also use else because it puts my return statements at the same level
of indentation, which I find more readable, since logically they're
equivalent.

> Am I the only one? ;)

One can only hope! <wink>

Jeremy

0 new messages