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.
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