alwbtc
alwbtc

Reputation: 29495

How to check if all elements of a list match a condition?

I have a list that contains many sub-lists of 3 elements each, like:

my_list = [["a", "b", 0], ["c", "d", 0], ["e", "f", 0], .....]

The last element of each sub-list is a sort of flag, which is initially 0 for each sub-list. As my algorithm progresses, I want to check whether this flag is 0 for at least one element. Currently I use a while loop, like so:

def check(list_):
    for item in list_:
        if item[2] == 0:
            return True
    return False

The overall algorithm loops as long as that condition is satisfied, and sets some of the flags in each iteration:

while check(my_list):
    for item in my_list:
        if condition:
            item[2] = 1
        else:
            do_sth()

Because it causes problems to remove elements from the list while iterating over it, I use these flags to keep track of elements that have already been processed.

How can I simplify or speed up the code?


See also Pythonic way of checking if a condition holds for any element of a list for checking the condition for any element. Keep in mind that "any" and "all" checks are related through De Morgan's law, just as "or" and "and" are related.

Existing answers here use the built-in function all to do the iteration. See How do Python's any and all functions work? for an explanation of all and its counterpart, any.

If the condition you want to check is "is found in another container", see How to check if all of the following items are in a list? and its counterpart, How to check if one of the following items is in a list?. Using any and all will work, but more efficient solutions are possible.

Upvotes: 326

Views: 562058

Answers (5)

Gareth Latty
Gareth Latty

Reputation: 89097

The best answer here is to use all(), which is the builtin for this situation. We combine this with a generator expression to produce the result you want cleanly and efficiently. For example:

>>> items = [[1, 2, 0], [1, 2, 0], [1, 2, 0]]
>>> all(flag == 0 for (_, _, flag) in items)
True
>>> items = [[1, 2, 0], [1, 2, 1], [1, 2, 0]]
>>> all(flag == 0 for (_, _, flag) in items)
False

Note that all(flag == 0 for (_, _, flag) in items) is directly equivalent to all(item[2] == 0 for item in items), it's just a little nicer to read in this case.

And, for the filter example, a list comprehension (of course, you could use a generator expression where appropriate):

>>> [x for x in items if x[2] == 0]
[[1, 2, 0], [1, 2, 0]]

If you want to check at least one element is 0, the better option is to use any() which is more readable:

>>> any(flag == 0 for (_, _, flag) in items)
True

Upvotes: 562

mulllhausen
mulllhausen

Reputation: 4435

this way is a bit more flexible than using all():

my_list = [[1, 2, 0], [1, 2, 0], [1, 2, 0]]
all_zeros = False if False in [x[2] == 0 for x in my_list] else True
any_zeros = True if True in [x[2] == 0 for x in my_list] else False

or more succinctly:

all_zeros = not False in [x[2] == 0 for x in my_list]
any_zeros = 0 in [x[2] for x in my_list]

Upvotes: 1

Learner
Learner

Reputation: 5302

Another way to use itertools.ifilter. This checks truthiness and process (using lambda)

Sample-

for x in itertools.ifilter(lambda x: x[2] == 0, my_list):
    print x

Upvotes: 0

Hampus Nilsson
Hampus Nilsson

Reputation: 6832

If you want to check if any item in the list violates a condition use all:

if all([x[2] == 0 for x in lista]):
    # Will run if all elements in the list has x[2] = 0 (use not to invert if necessary)

To remove all elements not matching, use filter

# Will remove all elements where x[2] is 0
listb = filter(lambda x: x[2] != 0, listb)

Upvotes: 31

Hedde van der Heide
Hedde van der Heide

Reputation: 22469

You could use itertools's takewhile like this, it will stop once a condition is met that fails your statement. The opposite method would be dropwhile

for x in itertools.takewhile(lambda x: x[2] == 0, list)
    print x

Upvotes: 8

Related Questions