builtin functions for and and or?

R

Roose

I need this a lot: a one line way to do a n-ary and or 'or'.

e.g.,

result = True
for x in L:
if not boolean_function(x):
result = False

or
reduce(operator.__and__, [boolean_function(x) for x in L)

So usually I just write a little function any( L, boolean_function =
identity ) or all( ... ). But I am kind of sick of doing that all the
time -- does it exist anywhere in the Python libraries? It seems really
common to me.

The first way isn't satisfactory because it takes so many lines for what is
essentially one "primitive" operation. The second way isn't great because
it is not as readable and many readers don't like to see reduce, even if it
is a common idiom like that. Also I don't believe it short circuits.
 
D

Diez B. Roggisch

So usually I just write a little function any( L, boolean_function =
identity ) or all( ... ). But I am kind of sick of doing that all the
time -- does it exist anywhere in the Python libraries? It seems really
common to me.

Put things into your own module and add it to your python path. Then you
only have to write it once.
The first way isn't satisfactory because it takes so many lines for what
is
essentially one "primitive" operation. The second way isn't great because
it is not as readable and many readers don't like to see reduce, even if
it
is a common idiom like that. Also I don't believe it short circuits.

It doesn't but so doesn't your loop example. Put a break in there once
Result is False.
 
M

Michael Hartl

I warmly recommend downloading Peter Norvig's Python utilities file
(http://aima.cs.berkeley.edu/python/utils.py) and putting it on your
Python path. (E.g., in bash, put a line like

export PYTHONPATH="/path/to/utilities_directory"

in your .bashrc file.) The utils.py file defines many useful
functions, including the ones you want:

# def every(predicate, seq):
# """True if every element of seq satisfies predicate.
# Ex: every(callable, [min, max]) ==> 1; every(callable, [min, 3])
==> 0
# """
# for x in seq:
# if not predicate(x): return False
# return True
#
# def some(predicate, seq):
# """If some element x of seq satisfies predicate(x), return
predicate(x).
# Ex: some(callable, [min, 3]) ==> 1; some(callable, [2, 3]) ==> 0
# """
# for x in seq:
# px = predicate(x)
# if px: return px
# return False

Michael
 
B

Brian Beck

Roose said:
I need this a lot: a one line way to do a n-ary and or 'or'.

Looks like there are itertools recipes for those, similar to what
Michael just posted. Taken from here:
http://docs.python.org/lib/itertools-recipes.html

def all(seq, pred=bool):
"Returns True if pred(x) is True for every element in the iterable"
for elem in ifilterfalse(pred, seq):
return False
return True

def any(seq, pred=bool):
"Returns True if pred(x) is True for at least one element in the
iterable"
for elem in ifilter(pred, seq):
return True
return False
 
B

Brian Beck

Brian said:
def all(seq, pred=bool):
"Returns True if pred(x) is True for every element in the iterable"
for elem in ifilterfalse(pred, seq):
return False
return True

def any(seq, pred=bool):
"Returns True if pred(x) is True for at least one element in the
iterable"
for elem in ifilter(pred, seq):
return True
return False

I should probably note, you'll have to

from itertools import ifilter, ifilterfalse

to use these.
 
S

Steven Bethard

Roose said:
I need this a lot: a one line way to do a n-ary and or 'or'.

e.g.,

result = True
for x in L:
if not boolean_function(x):
result = False

or
reduce(operator.__and__, [boolean_function(x) for x in L)

Can you use itertools?

py> def boolfn(x):
.... print "boolfn: %r" % x
.... return bool(x)
....
py> True in itertools.imap(boolfn, ['a', '', 'b'])
boolfn: 'a'
True
py> True in itertools.imap(boolfn, ['', '', ''])
boolfn: ''
boolfn: ''
boolfn: ''
False
py> False in itertools.imap(boolfn, ['a', '', 'b'])
boolfn: 'a'
boolfn: ''
True
py> False in itertools.imap(boolfn, ['a', 'a', 'b'])
boolfn: 'a'
boolfn: 'a'
boolfn: 'b'
False

It even shortcircuits when appropriate.

Steve
 
B

Brian Beck

Roose said:
I need this a lot: a one line way to do a n-ary and or 'or'.

Here's a one-liner for the n-ary and:

bool(min(bool(x) for x in L))


py> bool(min(bool(x) for x in [1, 1, 1, 0]))
False
py> bool(min(bool(x) for x in [1, 1, 1, 1]))
True
py> bool(min(bool(x) for x in ['a', '', 'b', 'c']))
False
py> bool(min(bool(x) for x in ['a', 'b', 'c', 'd']))
True
 
S

Steven Bethard

Brian said:
Roose said:
I need this a lot: a one line way to do a n-ary and or 'or'.

Here's a one-liner for the n-ary and:

bool(min(bool(x) for x in L))

py> bool(min(bool(x) for x in [1, 1, 1, 0]))
False
py> bool(min(bool(x) for x in [1, 1, 1, 1]))
True
py> bool(min(bool(x) for x in ['a', '', 'b', 'c']))
False
py> bool(min(bool(x) for x in ['a', 'b', 'c', 'd']))
True

Another alternative:

not False in (bool(x) for x in L)

py> not False in (bool(x) for x in [1, 1, 1, 0])
False
py> not False in (bool(x) for x in [1, 1, 1, 1])
True
py> not False in (bool(x) for x in ['a', '', 'b', 'c'])
False
py> not False in (bool(x) for x in ['a', 'b', 'c', 'd'])
True

Note that this should short-circuit, where min won't.

Steve
 
J

John Machin

Michael said:
I warmly recommend downloading Peter Norvig's Python utilities file
(http://aima.cs.berkeley.edu/python/utils.py) and putting it on your
Python path. (E.g., in bash, put a line like

export PYTHONPATH="/path/to/utilities_directory"

in your .bashrc file.) The utils.py file defines many useful
functions, including the ones you want:

# def every(predicate, seq):
# """True if every element of seq satisfies predicate.
# Ex: every(callable, [min, max]) ==> 1; every(callable, [min, 3])
==> 0
# """
# for x in seq:
# if not predicate(x): return False
# return True
#
# def some(predicate, seq):
# """If some element x of seq satisfies predicate(x), return
predicate(x).
# Ex: some(callable, [min, 3]) ==> 1; some(callable, [2, 3]) ==> 0
# """
# for x in seq:
# px = predicate(x)
# if px: return px
# return False

What an interesting mixed API design. The every() function returns True
or False. However the "some" function returns the FIRST fat result if
it's true in the non-boolean sense, otherwise False.

Looks like there could theoretically be scope for two pairs of
functions, one returning strictly True/False, and the other pair
emulating chains of Python 'and's and 'or's.

I.e.
False or 0 or [] evaluates to []
0 or 5 or 6 evaluates to 5
42 and None and True evaluates to None
4 and 5 and 6 evaluates to 6

All very nice, but useful? Dubious. PEPpable? Nah, two thumbs down.

Diez's advice to the OP is sound: if it bothers you that much, mine the
net for, or write, routines that do exactly what you want, and put them
in your own utilities module.
 
B

Brian Beck

Steven said:
Another alternative:

not False in (bool(x) for x in L)

Note that this should short-circuit, where min won't.

Steve

Whoops, for some reason the thought that short-circuiting didn't apply
to And entered my mind while trying to post a nice solution. Hard to say
why considering I have to do stuff like this on a daily basis!

Ignore mine except as a novelty, then.
 
G

George Sakkis

Roose said:
I need this a lot: a one line way to do a n-ary and or 'or'.

e.g.,

result = True
for x in L:
if not boolean_function(x):
result = False

or
reduce(operator.__and__, [boolean_function(x) for x in L)

So usually I just write a little function any( L, boolean_function =
identity ) or all( ... ). But I am kind of sick of doing that all the
time -- does it exist anywhere in the Python libraries? It seems really
common to me.

The first way isn't satisfactory because it takes so many lines for what is
essentially one "primitive" operation. The second way isn't great because
it is not as readable and many readers don't like to see reduce, even if it
is a common idiom like that. Also I don't believe it short circuits.


You're right, it doesn't short circuit, as most of the examples posted above. Here's one that it
does:

from itertools import ifilter, dropwhile

def any(pred, iterable):
try: ifilter(pred,iterable).next()
except StopIteration: return False
else: return True

def all(pred, iterable):
try: dropwhile(pred,iterable).next()
except StopIteration: return True
else: return False


George
 
B

Brian Beck

George said:
You're right, it doesn't short circuit, as most of the examples posted above. Here's one that it
does:

...

I also looked into taking advantage of itertools' dropwhile, but the all
and any recipes included in the itertools documentation do short-circuit
and don't require the setup of a try/except/else.
 
B

bearophileHUGS

In Python there are so many ways to do things...
This looks like another one, I haven't tested it:

not False in imap(pred, iterable)

As usual tests are required to measure the faster one.
I agree with Roose, there are are some "primitive" operations (like
this, and flatten, partition, mass removal of keys from a dictionary,
and few others) that can be added to the language (but I'm still not
capabable of doing it myself, and Python is free, so it's not right to
ask people to work for free for us).

Bear hugs,
Bearophile
 
R

Roose

Diez B. Roggisch said:
Put things into your own module and add it to your python path. Then you
only have to write it once.

Well it's not as convenient as having it built in. The thing is I'm not
just writing for myself. I used it at my old job, and now I'm using it at
my new job. There's a requirement that the user shouldn't have to modify
his setup beyond installing Python to run any scripts. At my first job we
had one way of dealing with this. Now there is another way. And then I
need a way to deal with it at home with my personal stuff.

Also the stuff typically doesn't go under the Python dir, because that is
not mapped to source control. And anyway people don't like mixing in our
code with 3rd party code.

The result that the path of least resistance is just to copy in a 4 line
function or two into the program and be done with it, even though it goes
against my sense of aesthetics.

It would be a lot simpler if it was included in the distribution. I would
be willing to add it (even though it is completely trivial). I think it
would go fine in itertools (I would even put them as builtins, but I'm not
going to go there because probably not everyone uses it as often as I do).

What do people think? I have never done this, would I just write up a PEP?
 
R

Roose

Yeah, as we can see there are a million ways to do it. But none of them are
as desirable as just having a library function to do the same thing. I'd
argue that since there are so many different ways, we should just collapse
them into one: any() and all(). That is more in keeping with the python
philosophy I suppose -- having one canonical way to do things. Otherwise
you could see any of these several ways of doing it in any program, and each
time you have to make sure it's doing what you think. Each of them requies
more examination than is justified for such a trivial operation. And this
definitely hurts the readability of the program.
 
M

Michael Spencer

Roose said:
Yeah, as we can see there are a million ways to do it. But none of them are
as desirable as just having a library function to do the same thing. I'd
argue that since there are so many different ways, we should just collapse
them into one: any() and all(). That is more in keeping with the python
philosophy I suppose -- having one canonical way to do things. Otherwise
you could see any of these several ways of doing it in any program, and each
time you have to make sure it's doing what you think. Each of them requies
more examination than is justified for such a trivial operation. And this
definitely hurts the readability of the program.
Previous discussion on this topic:
http://groups-beta.google.com/group/comp.lang.python/msg/a76b4c2caf6c435c

Michael
 
R

Roose

Previous discussion on this topic:

OK, well then. That's really the exact same thing, down to the names of the
functions. So what ever happened to that? That was over a year ago! I
don't see any mention of it in PEP 289?

http://www.python.org/peps/pep-0289.html

It would be hard to imagine such a trivial change being rejected, if it were
in its own namespace. Did it just happen that no one implemented it?

Or it looks like no one could agree on the names? From that thread, I see
any/all, anytrue/alltrue, forall/exists. Either of the first two is fine
with me.
 
M

Michael Spencer

N

Nick Coghlan

Roose said:
It would be a lot simpler if it was included in the distribution. I would
be willing to add it (even though it is completely trivial). I think it
would go fine in itertools (I would even put them as builtins, but I'm not
going to go there because probably not everyone uses it as often as I do).

What do people think? I have never done this, would I just write up a PEP?

I've posted a question to py-dev about it. If Raymond (the itertools maintainer)
is supportive, then a PEP may not be needed. If not. . . yeah, a PEP would
probably be required.

Cheers,
Nick.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top