A and B but not C in list

Discussion in 'Python' started by CM, Jan 23, 2011.

  1. CM

    CM Guest

    In Python, is there a recommended way to write conditionals of the
    form:

    "if A and B but not C or D in my list, do something." ?

    I may also have variations on this, like "if A but not B, C, or D".

    Do I have to just write out all the if and elifs with all possible
    conditions, or is there a handier and more code-maintainable way to
    deal with this?

    Thanks.
    CM, Jan 23, 2011
    #1
    1. Advertising

  2. On 01/23/2011 04:05 PM, CM wrote:
    > In Python, is there a recommended way to write conditionals of the
    > form:
    >
    > "if A and B but not C or D in my list, do something." ?
    >
    > I may also have variations on this, like "if A but not B, C, or D".
    >
    > Do I have to just write out all the if and elifs with all possible
    > conditions, or is there a handier and more code-maintainable way to
    > deal with this?
    >
    > Thanks.
    >
    >
    >
    >


    if (A in list and B in list) and (C not in list or D not in list):
    pass

    I'm sure the gurus on this list can come up with something better.
    Corey Richardson, Jan 23, 2011
    #2
    1. Advertising

  3. CM

    Chris Rebert Guest

    On Sun, Jan 23, 2011 at 1:05 PM, CM <> wrote:
    > In Python, is there a recommended way to write conditionals of the
    > form:
    >
    > "if A and B but not C or D in my list, do something."  ?
    >
    > I may also have variations on this, like "if A but not B, C, or D".
    >
    > Do I have to just write out all the if and elifs with all possible
    > conditions, or is there a handier and more code-maintainable way to
    > deal with this?


    Assuming your conditions all involve membership testing...
    Use the built-in any() and all() functions. For your first example:

    wanteds = [A, B]
    unwanteds = [C, D]
    if all(wanted in your_list for wanted in wanteds) and \
    not any(unwanted in your_list for unwanted in unwanteds):
    do_whatever()

    You could pull this out into a separate function if you wish.

    Cheers,
    Chris
    --
    http://blog.rebertia.com
    Chris Rebert, Jan 23, 2011
    #3
  4. On Sun, 23 Jan 2011 22:34:33 +0100, Christian Heimes wrote:

    > It's easier and faster if you convert the lists to sets first:
    >
    > your_set = set(your_list)
    >
    > if your_set.issuperset(set([A, B])) and your_set.isdisjoint(set([C,
    > D])):
    > ...


    "Easier" is a close thing. I find this easier to remember and write than
    set processing, even if it is a couple of characters longer:

    if all(x in your_list for x in (A, B)) and not any(x in your_list for x
    in (C, D)):
    ...

    And as for "faster", surely that will depend on the number of elements in
    your_list? The conversion from list to set doesn't happen for free, and
    it's likely that for small enough lists, that time may exceed any time
    savings you would otherwise gain.


    --
    Steven
    Steven D'Aprano, Jan 23, 2011
    #4
  5. CM

    Terry Reedy Guest

    On 1/23/2011 4:05 PM, CM wrote:
    > In Python, is there a recommended way to write conditionals of the
    > form:
    >
    > "if A and B but not C or D in my list, do something." ?
    >
    > I may also have variations on this, like "if A but not B, C, or D".
    >
    > Do I have to just write out all the if and elifs with all possible
    > conditions, or is there a handier and more code-maintainable way to
    > deal with this?


    The straightforward code

    if a in L and b in L and c not in L and d not in L

    scans the list 4 times. One scan be be done generically as follows:

    def req_pro(iterable, required = set(), prohibited = set()):
    for item in iterable:
    if item in prohibited:
    return False
    elif item in required:
    required.remove(item)
    else:
    return not required # should now be empty

    if req_pro(my_list, {A,B}, {C,D}): ...
    # untested, of course..

    --
    Terry Jan Reedy
    Terry Reedy, Jan 24, 2011
    #5
  6. CM

    Ian Kelly Guest

    On Sun, Jan 23, 2011 at 2:34 PM, Christian Heimes <> wrote:
    > your_set = set(your_list)
    >
    > if your_set.issuperset(set([A, B])) and your_set.isdisjoint(set([C, D])):


    if your_set.intersection([A, B, C, D]) == set([A, B]):
    ...

    Cheers,
    Ian
    Ian Kelly, Jan 24, 2011
    #6
  7. CM

    Peter Otten Guest

    Ian Kelly wrote:

    > On Sun, Jan 23, 2011 at 2:34 PM, Christian Heimes <>
    > wrote:
    >> your_set = set(your_list)
    >>
    >> if your_set.issuperset(set([A, B])) and your_set.isdisjoint(set([C, D])):

    >
    > if your_set.intersection([A, B, C, D]) == set([A, B]):
    > ...


    You can avoid converting your_list to a set with (using 2.7/3.x notation)

    if {A, B, C, D}.intersection(your_list) == {A, B}:
    ...

    The items in your_list still have to be hashable, so the approach is not as
    general as

    if (all(required in your_list for required in (A, B)) and
    not any(forbidden in your_list for forbidden in (C, D))):
    ...

    or similar.

    Also, it's not as easy to understand, so don't forget the explaining comment
    if you use the set-based approach.

    Peter
    Peter Otten, Jan 24, 2011
    #7
  8. CM

    Boris Borcic Guest

    Terry Reedy wrote:
    >
    > The straightforward code
    >
    > if a in L and b in L and c not in L and d not in L
    >
    > scans the list 4 times.


    of course for a single scan one can setify the list and write

    S=set(L)
    if a in S and b in S and c not in S and d not in S

    or even, I guess, something like

    {a,b} <= S and not S & {c,d}

    also, I suppose that in some settings a,b,c,d could be made to belong to a class
    that has defined eg

    __nonzero__ = __bool__ = S.__contains__

    so that the if statement would become

    if a and b and not c and not d

    btw, did anybody ask the OP which if any of A,B,C,D otoh and L otoh would vary
    fastest ?

    Whatever, BB
    Boris Borcic, Jan 24, 2011
    #8
  9. Terry Reedy <> writes:

    > On 1/23/2011 4:05 PM, CM wrote:
    >> In Python, is there a recommended way to write conditionals of the
    >> form:
    >>
    >> "if A and B but not C or D in my list, do something." ?
    >>
    >> I may also have variations on this, like "if A but not B, C, or D".
    >>
    >> Do I have to just write out all the if and elifs with all possible
    >> conditions, or is there a handier and more code-maintainable way to
    >> deal with this?

    >
    > The straightforward code
    >
    > if a in L and b in L and c not in L and d not in L
    >
    > scans the list 4 times. One scan be be done generically as follows:
    >
    > def req_pro(iterable, required = set(), prohibited = set()):
    > for item in iterable:
    > if item in prohibited:
    > return False
    > elif item in required:
    > required.remove(item)
    > else:
    > return not required # should now be empty
    >
    > if req_pro(my_list, {A,B}, {C,D}): ...
    > # untested, of course..


    But what's better? Four fast list scans or one slow one?

    --
    Arnaud
    Arnaud Delobelle, Jan 26, 2011
    #9
  10. CM

    CM Guest

    Thanks, everyone, for your suggestions.

    -Che
    CM, Jan 28, 2011
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?SlQ=?=
    Replies:
    0
    Views:
    2,159
    =?Utf-8?B?SlQ=?=
    Mar 21, 2006
  2. Ollie
    Replies:
    0
    Views:
    367
    Ollie
    Oct 2, 2003
  3. python
    Replies:
    7
    Views:
    304
    Bruno Desthuilliers
    Jun 3, 2006
  4. David Wang
    Replies:
    0
    Views:
    728
    David Wang
    Dec 1, 2006
  5. Travis
    Replies:
    6
    Views:
    542
    Markus Schoder
    Jun 28, 2007
Loading...

Share This Page