Function to check that a Python list contains only True and then only False I would like to only allow lists where the first n elements are True and then all of the remaining elements are False. I want lists like these examples to return True:


[]
[True]
[False]
[False, False]
[True, False]
[True, False, False]
[True, True, True, False]


And lists like these to return False:


[False, True]
[True, False, True]


That is, any list that can we written as [True] * n + [False] * m for n, m integers in the interval [0, infty).

I am currently using a function called check_true_then_false, but I feel like there is probably a neater way of doing this. The code doesn't need to be fast, as this will only be run once (not inside a loop) and the lists will short (single digit lengths).

def check_true_then_false(x):
    n_trues = sum(x)
    should_be_true = x[:n_trues]  # get the first n items
    should_be_false = x[n_trues:len(x)]  # get the remaining items
    # return True only if all of the first n elements are True and the remaining
    # elements are all False
    return all(should_be_true) and not any(should_be_false)


Testing shows that it produces the correct output:

test_cases = [[True],
              [False],
              [True, False],
              [True, False, False],
              [True, True, True, False],
              [False, True],
              [True, False, True]]
print([check_true_then_false(test_case) for test_case in test_cases])
# expected output: [True, True, True, True, True, False, False]
You can just use x[n_trues:] rather than x[n_trues:len(x)].
Your comments don't really say more than the code. And so I'd recommend removing the comments.
If you want to keep your code documented use docstrings, which can be exported to your documentation via tools like Sphinx.
As commented by Konrad Rudolph, you can remove the and not any(should_be_false) as this will always fail if the all fails.




def check_true_then_false(x):
    """Check first n values are True and the rest are False."""
    return all(x[:sum(x)])




If you want your code to work with iterators, not just sequences then you can instead use:

def check_true_then_false(it):
    """Check first n values are True and the rest are False."""
    it = iter(it)
    # Takes advantage of the iterating side effect, where it consumes the iterator.
    # This allows `all` to simultaneously checks `it` starts with trues and advances `it`.
    return all(it) or not any(it)


For the following two inputs all will result in:

&gt;&gt;&gt; all([True] * n)
True
&gt;&gt;&gt; all([True] * n + [False, ...])
False


However it will mean that it is still [...] as all and any are lazy. Meaning that we just need to check the rest are false. Meaning all slices the iterator for you without you having to. Leaving any with:

&gt;&gt;&gt; any([False] * n)
False
&gt;&gt;&gt; any([False] * n + [True, ...])
True