Pythonic way of saying 'at least one of a, b, or c is in some_list'

C

cbrown

It's clear but tedious to write:

if 'monday" in days_off or "tuesday" in days_off:
doSomething

I currently am tending to write:

if any([d for d in ['monday', 'tuesday'] if d in days_off]):
doSomething

Is there a better pythonic idiom for this situation?

Cheers - Chas
 
J

John Posner

It's clear but tedious to write:

if 'monday" in days_off or "tuesday" in days_off:
doSomething

I currently am tending to write:

if any([d for d in ['monday', 'tuesday'] if d in days_off]):
doSomething

Is there a better pythonic idiom for this situation?

Clunky, but it might prompt you to think of a better idea: convert the
lists to sets, and take their intersection.

-John
 
C

cbrown

It's clear but tedious to write:
if 'monday" in days_off or "tuesday" in days_off:
     doSomething
I currently am tending to write:
if any([d for d in ['monday', 'tuesday'] if d in days_off]):
     doSomething
Is there a better pythonic idiom for this situation?

Clunky, but it might prompt you to think of a better idea: convert the
lists to sets, and take their intersection.

-John

I thought of that as well, e.g.:

if set(["monday,"tuesday']).intersection(set(days_off)):
doSomething

but those extra recasts to set() make it unaesthetic to me; and worse

if not set(["monday,"tuesday']).isdisjoint(set(days_off)):
doSomething

is bound to confuse most readers.

Cheers - Chjas
 
C

Chris Rebert

It's clear but tedious to write:
if 'monday" in days_off or "tuesday" in days_off:
     doSomething
I currently am tending to write:
if any([d for d in ['monday', 'tuesday'] if d in days_off]):
     doSomething
Is there a better pythonic idiom for this situation?

Clunky, but it might prompt you to think of a better idea: convert the
lists to sets, and take their intersection.

-John

I thought of that as well, e.g.:

if set(["monday,"tuesday']).intersection(set(days_off)):
   doSomething

but those extra recasts to set() make it unaesthetic to me; and worse

Why not make days_off a set in the first place? Isn't it,
conceptually, a set of days off?
if not set(["monday,"tuesday']).isdisjoint(set(days_off)):
   doSomething

is bound to confuse most readers.

This way is more straightforward:

if set(["monday", "tuesday"]) & days_off:

Cheers,
Chris
 
N

nn

On 10/28/2010 12:16 PM, (e-mail address removed) wrote:
It's clear but tedious to write:
if 'monday" in days_off or "tuesday" in days_off:
     doSomething
I currently am tending to write:
if any([d for d in ['monday', 'tuesday'] if d in days_off]):
     doSomething
Is there a better pythonic idiom for this situation?
Clunky, but it might prompt you to think of a better idea: convert the
lists to sets, and take their intersection.

I thought of that as well, e.g.:

if set(["monday,"tuesday']).intersection(set(days_off)):
    doSomething

but those extra recasts to set() make it unaesthetic to me; and worse

if not set(["monday,"tuesday']).isdisjoint(set(days_off)):
    doSomething

is bound to confuse most readers.

Cheers - Chjas

If you have Python 2.7 or newer you don't need to recast:

if {"monday", "tuesday"}.intersection(days_off): doSomething
 
C

cbrown

On 10/28/2010 12:16 PM, (e-mail address removed) wrote:
It's clear but tedious to write:
if 'monday" in days_off or "tuesday" in days_off:
     doSomething
I currently am tending to write:
if any([d for d in ['monday', 'tuesday'] if d in days_off]):
     doSomething
Is there a better pythonic idiom for this situation?
Clunky, but it might prompt you to think of a better idea: convert the
lists to sets, and take their intersection.
-John
I thought of that as well, e.g.:
if set(["monday,"tuesday']).intersection(set(days_off)):
   doSomething
but those extra recasts to set() make it unaesthetic to me; and worse

Why not make days_off a set in the first place? Isn't it,
conceptually, a set of days off?

That makes sense in my example situation; but often this construct
appears on the fly when the list is a preferred to be a list for other
reasons.
if not set(["monday,"tuesday']).isdisjoint(set(days_off)):
   doSomething
is bound to confuse most readers.

This way is more straightforward:

if set(["monday", "tuesday"]) & days_off:

That's much nicer, even if I have to recast days_off as set(days_off).

Cheers - Chas
 
A

Arnaud Delobelle

It's clear but tedious to write:

if 'monday" in days_off or "tuesday" in days_off:
doSomething

I currently am tending to write:

if any([d for d in ['monday', 'tuesday'] if d in days_off]):
doSomething

Is there a better pythonic idiom for this situation?

The latter can be written more concisely:

if any(d in days_off for d in ['monday', 'tuesday']):
# do something
 
J

John Nagle

It's clear but tedious to write:

if 'monday" in days_off or "tuesday" in days_off:
doSomething

I currently am tending to write:

if any([d for d in ['monday', 'tuesday'] if d in days_off]):
doSomething

Is there a better pythonic idiom for this situation?

Clunky, but it might prompt you to think of a better idea: convert the
lists to sets, and take their intersection.

-John

d1 = set('monday','tuesday')
days_off = set('saturday','sunday')

if not d1.isdisjoint(days_off) :
...

This is cheaper than intersection, since it doesn't have to allocate
and construct a set. It just tests whether any element in the smaller of
the two sets is in the larger one.

John Nagle
 
P

Paul Rubin

John Nagle said:
d1 = set('monday','tuesday')
days_off = set('saturday','sunday')
if not d1.isdisjoint(days_off) :...
This is cheaper than intersection, since it doesn't have to
allocate and construct a set. It just tests whether any element in the
smaller of the two sets is in the larger one.

I wonder what the complexity is, since the simplest implementation using
the dict-like features of sets is quadratic. There is of course an
obvious n log n implementation involving sorting.
 
C

cbrown

It's clear but tedious to write:
if 'monday" in days_off or "tuesday" in days_off:
    doSomething
I currently am tending to write:
if any([d for d in ['monday', 'tuesday'] if d in days_off]):
    doSomething
Is there a better pythonic idiom for this situation?

The latter can be written more concisely:

    if any(d in days_off for d in ['monday', 'tuesday']):
        # do something

For the list comprehension approach, I like this much better. In the
situation I am thinking of, it very naturally reads as 'if any of my
days off is monday or tuesday', rather than the logically equivalent,
but somewhat convoluted 'if any of monday or tuesday is one of my days
off'.

I should note that efficiency is not an issue to me here; this is for
when you have, say, a list user_options of at most around 15 options
or so, and you want to perform some action if one or more of a, b, or
c is an option listed in user_options. Big O notation isn't so
relevant as readability and 'naturalness'.

Cheers - Chas
 
C

Carl Banks

I wonder what the complexity is, since the simplest implementation using
the dict-like features of sets is quadratic.

I don't how isdisjoint is implemented, nor exactly what you mean by
dict-like features, but this implementation is linear on length of
smaller_set in the typical case:

def disjoint(smaller_set,larger_set):
for item in smaller_set:
if item in larger_set:
return False
return True


(Unless you meant worst case, which I don't consider important for
dictionary lookups.)


Carl Banks
 
H

HEK

It's clear but tedious to write:

if 'monday" in days_off or "tuesday" in days_off:
    doSomething

I currently am tending to write:

if any([d for d in ['monday', 'tuesday'] if d in days_off]):
    doSomething

Is there a better pythonic idiom for this situation?

Cheers - Chas

The most pythonic way is the following:

class anyof(set):
def __contains__(self,item):
if isinstance(item,anyof):
for it in item:
if self.__contains__(it):
return True
else:
return False
return super(anyof,self).__contains__(item)

daysoff=anyof(['Saterday','Sunday'])
assert anyof(['monday','tuesday']) in daysoff

best regards
Hassan
 
S

Steven D'Aprano

It's clear but tedious to write:

if 'monday" in days_off or "tuesday" in days_off:
doSomething

I currently am tending to write:

if any([d for d in ['monday', 'tuesday'] if d in days_off]):
doSomething


Use a simple generator expression and any.

if any(day in days_off for day in ['monday', 'tuesday']):
doSomething

You (partially) defeat the short-circuiting behaviour of any() by using a
list comprehension.

If you have a lot of items to test against, make days_off a set instead
of a list, which makes each `in` test O(1) instead of O(N). For small N,
the overhead of creating the set is probably going to be bigger than the
saving, so stick to a list.

Other than that, doing set operations is overkill -- it obfuscates the
intention of the code for very little gain, and possibly negative gain.
And as for the suggestion that you create a helper class to do the work,
that's surely the recommended way to do it in Java rather than Python.
 
A

Adam Przybyla

It's clear but tedious to write:

if 'monday" in days_off or "tuesday" in days_off:
doSomething

I currently am tending to write:

if any([d for d in ['monday', 'tuesday'] if d in days_off]):
doSomething

Is there a better pythonic idiom for this situation?
... hmmm, try this:
if set(['monday', 'tuesday'])&set(days_off):
dosomething
Regards
Adam Przybyla
 
C

cbrown

It's clear but tedious to write:
if 'monday" in days_off or "tuesday" in days_off:
    doSomething
I currently am tending to write:
if any([d for d in ['monday', 'tuesday'] if d in days_off]):
    doSomething

Use a simple generator expression and any.

if any(day in days_off for day in ['monday', 'tuesday']):
    doSomething

You (partially) defeat the short-circuiting behaviour of any() by using a
list comprehension.

Good point, thanks.
If you have a lot of items to test against, make days_off a set instead
of a list, which makes each `in` test O(1) instead of O(N). For small N,
the overhead of creating the set is probably going to be bigger than the
saving, so stick to a list.

Other than that, doing set operations is overkill -- it obfuscates the
intention of the code for very little gain, and possibly negative gain.
And as for the suggestion that you create a helper class to do the work,
that's surely the recommended way to do it in Java rather than Python.

Agreed. In the situation I am thinking of, N is generally very small,
and readability trumps execution speed.

Cheers - Chas

 
L

Lawrence D'Oliveiro

In message
<[email protected]>,
I should note that efficiency is not an issue to me here; this is for
when you have, say, a list user_options of at most around 15 options
or so, and you want to perform some action if one or more of a, b, or
c is an option listed in user_options. Big O notation isn't so
relevant as readability and 'naturalness'.

I must say this whole thread has turned into a massive bikeshedding
exercise.
 
C

cbrown

In message



I must say this whole thread has turned into a massive bikeshedding
exercise.

Agreed that, to paraphrase RWE, a foolish insistence on big O
valuation is the hobgoblin of etc. On the other hand, I got a
reasonable answer to my question:

if any(option in ['optionA', 'optionB', 'optionC']
for option in supplied_options):
first_do_something_those_options_all_require()
if 'optionA' in supplied_options:
do_optionA_specific_stuff()
<and so on and so forth...>

which is quite readable and flexible as an idiom, and so I am
satisfied overall.

Cheers - Chas
 

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

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top