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

alwbtc picture alwbtc · May 19, 2012 · Viewed 336.1k times · Source

I have a list consisting of like 20000 lists. I use each list's 3rd element as a flag. I want to do some operations on this list as long as at least one element's flag is 0, it's like:

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

In the beginning, all flags are 0. I use a while loop to check if at least one element's flag is 0:

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

If check(my_list) returns True, then I continue working on my list:

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

Actually, I wanted to remove an element in my_list as I iterated over it, but I'm not allowed to remove items as I iterate over it.

Original my_list didn't have flags:

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

Since I couldn't remove elements as I iterated over it, I invented these flags. But the my_list contains many items, and while loop reads all of them at each for loop, and it consumes lots of time! Do you have any suggestions?

Answer

Gareth Latty picture Gareth Latty · May 19, 2012

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