Function to check that a Python list contains only True and then only False
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
8
down vote
favorite
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]
python python-3.x
 |Â
show 3 more comments
up vote
8
down vote
favorite
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]
python python-3.x
Sorry it didn't work out. Try again on SO. I have a concrete answer I'd like to post that I think would work for this site, but would also work for SO.
– Mad Physicist
Sep 4 at 3:41
Ping me if you decide to make the post again.
– Mad Physicist
Sep 4 at 3:42
1
I've just removed this question from SO because I was told it was better suited to Code Review, so I don't know where to post it anymore.
– Hasnep
Sep 4 at 3:51
5
Could you clarify the requirements? Are,
[True]
, and[False, False]
acceptable?
– 200_success
Sep 4 at 10:06
1
Another way of explaining is any list that can we written as[True] * n + [False] * m
forn
,m
integers in the interval [0, infty).
– Hasnep
Sep 5 at 2:18
 |Â
show 3 more comments
up vote
8
down vote
favorite
up vote
8
down vote
favorite
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]
python python-3.x
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]
python python-3.x
edited Sep 5 at 2:15
asked Sep 4 at 3:26


Hasnep
435
435
Sorry it didn't work out. Try again on SO. I have a concrete answer I'd like to post that I think would work for this site, but would also work for SO.
– Mad Physicist
Sep 4 at 3:41
Ping me if you decide to make the post again.
– Mad Physicist
Sep 4 at 3:42
1
I've just removed this question from SO because I was told it was better suited to Code Review, so I don't know where to post it anymore.
– Hasnep
Sep 4 at 3:51
5
Could you clarify the requirements? Are,
[True]
, and[False, False]
acceptable?
– 200_success
Sep 4 at 10:06
1
Another way of explaining is any list that can we written as[True] * n + [False] * m
forn
,m
integers in the interval [0, infty).
– Hasnep
Sep 5 at 2:18
 |Â
show 3 more comments
Sorry it didn't work out. Try again on SO. I have a concrete answer I'd like to post that I think would work for this site, but would also work for SO.
– Mad Physicist
Sep 4 at 3:41
Ping me if you decide to make the post again.
– Mad Physicist
Sep 4 at 3:42
1
I've just removed this question from SO because I was told it was better suited to Code Review, so I don't know where to post it anymore.
– Hasnep
Sep 4 at 3:51
5
Could you clarify the requirements? Are,
[True]
, and[False, False]
acceptable?
– 200_success
Sep 4 at 10:06
1
Another way of explaining is any list that can we written as[True] * n + [False] * m
forn
,m
integers in the interval [0, infty).
– Hasnep
Sep 5 at 2:18
Sorry it didn't work out. Try again on SO. I have a concrete answer I'd like to post that I think would work for this site, but would also work for SO.
– Mad Physicist
Sep 4 at 3:41
Sorry it didn't work out. Try again on SO. I have a concrete answer I'd like to post that I think would work for this site, but would also work for SO.
– Mad Physicist
Sep 4 at 3:41
Ping me if you decide to make the post again.
– Mad Physicist
Sep 4 at 3:42
Ping me if you decide to make the post again.
– Mad Physicist
Sep 4 at 3:42
1
1
I've just removed this question from SO because I was told it was better suited to Code Review, so I don't know where to post it anymore.
– Hasnep
Sep 4 at 3:51
I've just removed this question from SO because I was told it was better suited to Code Review, so I don't know where to post it anymore.
– Hasnep
Sep 4 at 3:51
5
5
Could you clarify the requirements? Are
, [True]
, and [False, False]
acceptable?– 200_success
Sep 4 at 10:06
Could you clarify the requirements? Are
, [True]
, and [False, False]
acceptable?– 200_success
Sep 4 at 10:06
1
1
Another way of explaining is any list that can we written as
[True] * n + [False] * m
for n
, m
integers in the interval [0, infty).– Hasnep
Sep 5 at 2:18
Another way of explaining is any list that can we written as
[True] * n + [False] * m
for n
, m
integers in the interval [0, infty).– Hasnep
Sep 5 at 2:18
 |Â
show 3 more comments
4 Answers
4
active
oldest
votes
up vote
13
down vote
accepted
- You can just use
x[n_trues:]
rather thanx[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 theall
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:
>>> all([True] * n)
True
>>> 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:
>>> any([False] * n)
False
>>> any([False] * n + [True, ...])
True
6
all(it) or not any(it)
is elegant! – It would detect["a", "b"]
as a valid list because it checks for truthiness rather than True/False, but from the Python point of view that is probably the “right thing.â€Â
– Martin R
Sep 4 at 8:46
2
Elegant but cryptic. I would be wary of using it in actual code. In the first bit of code (as in OP’s), you can omit the redundant test forand not any(…)
(assuming the list only contains bools).
– Konrad Rudolph
Sep 4 at 10:04
@KonradRudolph True, and true. I guess using a comment to decryptify it may help.
– Peilonrayz
Sep 4 at 10:19
2
In the comment, instead of sayingand slices it
I would use the phrasingand advances it
.
– Mathias Ettinger
Sep 4 at 16:48
@MathiasEttinger Yeah, that's probably a better way to describe it :)
– Peilonrayz
Sep 4 at 19:45
 |Â
show 2 more comments
up vote
8
down vote
Basically, you want your list of booleans to be sorted.
Specifically, since True > False
, you want your list to be sorted in decreasing order:
def check_true_then_false(booleans):
return booleans == sorted(booleans, reverse=True)
Done!
>>> 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])
[True, True, True, True, True, False, False]
2
This is a good answer as it expresses a higher level property of the desired code. The code is clearer because you get the "why", instead of just the "how", from reading it.
– lkraider
Sep 4 at 15:11
It may be more obvious if there is apartitioned(...)
function in Python (I don't know Python that well, but C++ hasstd::is_partitioned
). It's a bit tricky to think ofsorted
, as you wouldn't want to sort a list to create this pattern due to partitioning being a simpler algorithm.
– Justin
Sep 4 at 17:26
@Justin: You're right thatsorted
is a minimal overkill.is_partitioned
doesn't exist in standard Python as far as I know. Also, partition isn't enough :True
s should appear beforeFalse
s.
– Eric Duminil
Sep 4 at 17:47
@EricDuminil Any decent partition implementation should take a predicate that allows you to specify how to partition it. Also, FWIW, C++'sstd::partition
movestrue
elements beforefalse
elements.
– Justin
Sep 4 at 17:57
@Justin: Please ignore my last comment then. I learned something today.
– Eric Duminil
Sep 4 at 18:20
 |Â
show 4 more comments
up vote
5
down vote
Your code works correctly under the assumption that the given list
contains only True
or False
elements. For other lists it can return
“false positivesâ€Â
>>> check_true_then_false([1, 1, 0])
True
or abort with a runtime error:
>>> check_true_then_false(["a", "b"])
TypeError: unsupported operand type(s) for +: 'int' and 'str'
The function traverses the given list in order to find the number ofTrue
elements. It then creates two additional lists, which are also
traversed to check if all elements are True
resp. False
.
A more efficient way would be to iterate the given list only once:
- Find the first non-
True
element. If there is any then it must beFalse
. - Then find the next non-
False
element. There should not be any.
If either of the above iterations fails (and next()
raises aStopIteration
exception) then the list is of the required form, and
the function returns True
:
def check_true_then_false(x):
list_iter = iter(x)
try:
return (next(elem for elem in list_iter if elem is not True) is False
and next(elem for elem in list_iter if elem is not False) is False)
except StopIteration:
return True
Peilonrayz explained how to document the
function using docstrings. In addition, the test cases can also be
embedded into the docstrings, with doctest
:
def check_true_then_false(x):
"""Check first n values are True and the rest are False.
>>> check_true_then_false([True])
True
>>> check_true_then_false([False])
True
>>> check_true_then_false([False, True])
False
>>> check_true_then_false([True, False, True])
False
>>> check_true_then_false([1, 1, 0])
False
>>> check_true_then_false(["a", "b"])
False
"""
# ... Your code ...
if __name__ == "__main__":
import doctest
doctest.testmod()
This doesn’t correctly detect non-boolean values if the first non-True argument is not False. For example:check_true_then_false([True, True, "foo", False])
evaluates to True.
– Neil Roberts
Sep 4 at 10:21
@NeilRoberts: You are right (becausenext()
consumes that element). It should be fixed now (but lacks the elegance of Peilonrayz's solution).
– Martin R
Sep 4 at 11:01
add a comment |Â
up vote
1
down vote
You can make this more efficient by using a simple loop:
def check_true_then_false(x):
prev = True
for i in x:
current = bool(i)
if current and not prev:
# Found truthy element after falsy one.
return False
prev = current
return True
Tested here
This requires one full iteration and negligible memory in the worst case, while your solution requires 5 iterations (4 plus 1 over each of the split lists) and two lists that sum to the length of the original (somewhere on the order of double the memory).
Explicitly written out loops are often remarkably slow in Python, compared to the built in list handling functions; so much so that I wouldn't be comfortable betting that this is faster without a profiler. Nevertheless this is certainly more memory efficient than the original, is easy to read, is clear why it does what it claims including where it's an improvement on the original code. Overall I would definitely take something like this as a first implementation and then look for built in functions that replicate it to optimise.
– Josiah
Sep 5 at 7:24
add a comment |Â
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
13
down vote
accepted
- You can just use
x[n_trues:]
rather thanx[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 theall
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:
>>> all([True] * n)
True
>>> 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:
>>> any([False] * n)
False
>>> any([False] * n + [True, ...])
True
6
all(it) or not any(it)
is elegant! – It would detect["a", "b"]
as a valid list because it checks for truthiness rather than True/False, but from the Python point of view that is probably the “right thing.â€Â
– Martin R
Sep 4 at 8:46
2
Elegant but cryptic. I would be wary of using it in actual code. In the first bit of code (as in OP’s), you can omit the redundant test forand not any(…)
(assuming the list only contains bools).
– Konrad Rudolph
Sep 4 at 10:04
@KonradRudolph True, and true. I guess using a comment to decryptify it may help.
– Peilonrayz
Sep 4 at 10:19
2
In the comment, instead of sayingand slices it
I would use the phrasingand advances it
.
– Mathias Ettinger
Sep 4 at 16:48
@MathiasEttinger Yeah, that's probably a better way to describe it :)
– Peilonrayz
Sep 4 at 19:45
 |Â
show 2 more comments
up vote
13
down vote
accepted
- You can just use
x[n_trues:]
rather thanx[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 theall
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:
>>> all([True] * n)
True
>>> 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:
>>> any([False] * n)
False
>>> any([False] * n + [True, ...])
True
6
all(it) or not any(it)
is elegant! – It would detect["a", "b"]
as a valid list because it checks for truthiness rather than True/False, but from the Python point of view that is probably the “right thing.â€Â
– Martin R
Sep 4 at 8:46
2
Elegant but cryptic. I would be wary of using it in actual code. In the first bit of code (as in OP’s), you can omit the redundant test forand not any(…)
(assuming the list only contains bools).
– Konrad Rudolph
Sep 4 at 10:04
@KonradRudolph True, and true. I guess using a comment to decryptify it may help.
– Peilonrayz
Sep 4 at 10:19
2
In the comment, instead of sayingand slices it
I would use the phrasingand advances it
.
– Mathias Ettinger
Sep 4 at 16:48
@MathiasEttinger Yeah, that's probably a better way to describe it :)
– Peilonrayz
Sep 4 at 19:45
 |Â
show 2 more comments
up vote
13
down vote
accepted
up vote
13
down vote
accepted
- You can just use
x[n_trues:]
rather thanx[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 theall
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:
>>> all([True] * n)
True
>>> 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:
>>> any([False] * n)
False
>>> any([False] * n + [True, ...])
True
- You can just use
x[n_trues:]
rather thanx[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 theall
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:
>>> all([True] * n)
True
>>> 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:
>>> any([False] * n)
False
>>> any([False] * n + [True, ...])
True
edited Sep 4 at 19:45
answered Sep 4 at 8:31
Peilonrayz
24.7k336103
24.7k336103
6
all(it) or not any(it)
is elegant! – It would detect["a", "b"]
as a valid list because it checks for truthiness rather than True/False, but from the Python point of view that is probably the “right thing.â€Â
– Martin R
Sep 4 at 8:46
2
Elegant but cryptic. I would be wary of using it in actual code. In the first bit of code (as in OP’s), you can omit the redundant test forand not any(…)
(assuming the list only contains bools).
– Konrad Rudolph
Sep 4 at 10:04
@KonradRudolph True, and true. I guess using a comment to decryptify it may help.
– Peilonrayz
Sep 4 at 10:19
2
In the comment, instead of sayingand slices it
I would use the phrasingand advances it
.
– Mathias Ettinger
Sep 4 at 16:48
@MathiasEttinger Yeah, that's probably a better way to describe it :)
– Peilonrayz
Sep 4 at 19:45
 |Â
show 2 more comments
6
all(it) or not any(it)
is elegant! – It would detect["a", "b"]
as a valid list because it checks for truthiness rather than True/False, but from the Python point of view that is probably the “right thing.â€Â
– Martin R
Sep 4 at 8:46
2
Elegant but cryptic. I would be wary of using it in actual code. In the first bit of code (as in OP’s), you can omit the redundant test forand not any(…)
(assuming the list only contains bools).
– Konrad Rudolph
Sep 4 at 10:04
@KonradRudolph True, and true. I guess using a comment to decryptify it may help.
– Peilonrayz
Sep 4 at 10:19
2
In the comment, instead of sayingand slices it
I would use the phrasingand advances it
.
– Mathias Ettinger
Sep 4 at 16:48
@MathiasEttinger Yeah, that's probably a better way to describe it :)
– Peilonrayz
Sep 4 at 19:45
6
6
all(it) or not any(it)
is elegant! – It would detect ["a", "b"]
as a valid list because it checks for truthiness rather than True/False, but from the Python point of view that is probably the “right thing.â€Â– Martin R
Sep 4 at 8:46
all(it) or not any(it)
is elegant! – It would detect ["a", "b"]
as a valid list because it checks for truthiness rather than True/False, but from the Python point of view that is probably the “right thing.â€Â– Martin R
Sep 4 at 8:46
2
2
Elegant but cryptic. I would be wary of using it in actual code. In the first bit of code (as in OP’s), you can omit the redundant test for
and not any(…)
(assuming the list only contains bools).– Konrad Rudolph
Sep 4 at 10:04
Elegant but cryptic. I would be wary of using it in actual code. In the first bit of code (as in OP’s), you can omit the redundant test for
and not any(…)
(assuming the list only contains bools).– Konrad Rudolph
Sep 4 at 10:04
@KonradRudolph True, and true. I guess using a comment to decryptify it may help.
– Peilonrayz
Sep 4 at 10:19
@KonradRudolph True, and true. I guess using a comment to decryptify it may help.
– Peilonrayz
Sep 4 at 10:19
2
2
In the comment, instead of saying
and slices it
I would use the phrasing and advances it
.– Mathias Ettinger
Sep 4 at 16:48
In the comment, instead of saying
and slices it
I would use the phrasing and advances it
.– Mathias Ettinger
Sep 4 at 16:48
@MathiasEttinger Yeah, that's probably a better way to describe it :)
– Peilonrayz
Sep 4 at 19:45
@MathiasEttinger Yeah, that's probably a better way to describe it :)
– Peilonrayz
Sep 4 at 19:45
 |Â
show 2 more comments
up vote
8
down vote
Basically, you want your list of booleans to be sorted.
Specifically, since True > False
, you want your list to be sorted in decreasing order:
def check_true_then_false(booleans):
return booleans == sorted(booleans, reverse=True)
Done!
>>> 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])
[True, True, True, True, True, False, False]
2
This is a good answer as it expresses a higher level property of the desired code. The code is clearer because you get the "why", instead of just the "how", from reading it.
– lkraider
Sep 4 at 15:11
It may be more obvious if there is apartitioned(...)
function in Python (I don't know Python that well, but C++ hasstd::is_partitioned
). It's a bit tricky to think ofsorted
, as you wouldn't want to sort a list to create this pattern due to partitioning being a simpler algorithm.
– Justin
Sep 4 at 17:26
@Justin: You're right thatsorted
is a minimal overkill.is_partitioned
doesn't exist in standard Python as far as I know. Also, partition isn't enough :True
s should appear beforeFalse
s.
– Eric Duminil
Sep 4 at 17:47
@EricDuminil Any decent partition implementation should take a predicate that allows you to specify how to partition it. Also, FWIW, C++'sstd::partition
movestrue
elements beforefalse
elements.
– Justin
Sep 4 at 17:57
@Justin: Please ignore my last comment then. I learned something today.
– Eric Duminil
Sep 4 at 18:20
 |Â
show 4 more comments
up vote
8
down vote
Basically, you want your list of booleans to be sorted.
Specifically, since True > False
, you want your list to be sorted in decreasing order:
def check_true_then_false(booleans):
return booleans == sorted(booleans, reverse=True)
Done!
>>> 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])
[True, True, True, True, True, False, False]
2
This is a good answer as it expresses a higher level property of the desired code. The code is clearer because you get the "why", instead of just the "how", from reading it.
– lkraider
Sep 4 at 15:11
It may be more obvious if there is apartitioned(...)
function in Python (I don't know Python that well, but C++ hasstd::is_partitioned
). It's a bit tricky to think ofsorted
, as you wouldn't want to sort a list to create this pattern due to partitioning being a simpler algorithm.
– Justin
Sep 4 at 17:26
@Justin: You're right thatsorted
is a minimal overkill.is_partitioned
doesn't exist in standard Python as far as I know. Also, partition isn't enough :True
s should appear beforeFalse
s.
– Eric Duminil
Sep 4 at 17:47
@EricDuminil Any decent partition implementation should take a predicate that allows you to specify how to partition it. Also, FWIW, C++'sstd::partition
movestrue
elements beforefalse
elements.
– Justin
Sep 4 at 17:57
@Justin: Please ignore my last comment then. I learned something today.
– Eric Duminil
Sep 4 at 18:20
 |Â
show 4 more comments
up vote
8
down vote
up vote
8
down vote
Basically, you want your list of booleans to be sorted.
Specifically, since True > False
, you want your list to be sorted in decreasing order:
def check_true_then_false(booleans):
return booleans == sorted(booleans, reverse=True)
Done!
>>> 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])
[True, True, True, True, True, False, False]
Basically, you want your list of booleans to be sorted.
Specifically, since True > False
, you want your list to be sorted in decreasing order:
def check_true_then_false(booleans):
return booleans == sorted(booleans, reverse=True)
Done!
>>> 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])
[True, True, True, True, True, False, False]
answered Sep 4 at 13:03


Eric Duminil
1,9381613
1,9381613
2
This is a good answer as it expresses a higher level property of the desired code. The code is clearer because you get the "why", instead of just the "how", from reading it.
– lkraider
Sep 4 at 15:11
It may be more obvious if there is apartitioned(...)
function in Python (I don't know Python that well, but C++ hasstd::is_partitioned
). It's a bit tricky to think ofsorted
, as you wouldn't want to sort a list to create this pattern due to partitioning being a simpler algorithm.
– Justin
Sep 4 at 17:26
@Justin: You're right thatsorted
is a minimal overkill.is_partitioned
doesn't exist in standard Python as far as I know. Also, partition isn't enough :True
s should appear beforeFalse
s.
– Eric Duminil
Sep 4 at 17:47
@EricDuminil Any decent partition implementation should take a predicate that allows you to specify how to partition it. Also, FWIW, C++'sstd::partition
movestrue
elements beforefalse
elements.
– Justin
Sep 4 at 17:57
@Justin: Please ignore my last comment then. I learned something today.
– Eric Duminil
Sep 4 at 18:20
 |Â
show 4 more comments
2
This is a good answer as it expresses a higher level property of the desired code. The code is clearer because you get the "why", instead of just the "how", from reading it.
– lkraider
Sep 4 at 15:11
It may be more obvious if there is apartitioned(...)
function in Python (I don't know Python that well, but C++ hasstd::is_partitioned
). It's a bit tricky to think ofsorted
, as you wouldn't want to sort a list to create this pattern due to partitioning being a simpler algorithm.
– Justin
Sep 4 at 17:26
@Justin: You're right thatsorted
is a minimal overkill.is_partitioned
doesn't exist in standard Python as far as I know. Also, partition isn't enough :True
s should appear beforeFalse
s.
– Eric Duminil
Sep 4 at 17:47
@EricDuminil Any decent partition implementation should take a predicate that allows you to specify how to partition it. Also, FWIW, C++'sstd::partition
movestrue
elements beforefalse
elements.
– Justin
Sep 4 at 17:57
@Justin: Please ignore my last comment then. I learned something today.
– Eric Duminil
Sep 4 at 18:20
2
2
This is a good answer as it expresses a higher level property of the desired code. The code is clearer because you get the "why", instead of just the "how", from reading it.
– lkraider
Sep 4 at 15:11
This is a good answer as it expresses a higher level property of the desired code. The code is clearer because you get the "why", instead of just the "how", from reading it.
– lkraider
Sep 4 at 15:11
It may be more obvious if there is a
partitioned(...)
function in Python (I don't know Python that well, but C++ has std::is_partitioned
). It's a bit tricky to think of sorted
, as you wouldn't want to sort a list to create this pattern due to partitioning being a simpler algorithm.– Justin
Sep 4 at 17:26
It may be more obvious if there is a
partitioned(...)
function in Python (I don't know Python that well, but C++ has std::is_partitioned
). It's a bit tricky to think of sorted
, as you wouldn't want to sort a list to create this pattern due to partitioning being a simpler algorithm.– Justin
Sep 4 at 17:26
@Justin: You're right that
sorted
is a minimal overkill. is_partitioned
doesn't exist in standard Python as far as I know. Also, partition isn't enough : True
s should appear before False
s.– Eric Duminil
Sep 4 at 17:47
@Justin: You're right that
sorted
is a minimal overkill. is_partitioned
doesn't exist in standard Python as far as I know. Also, partition isn't enough : True
s should appear before False
s.– Eric Duminil
Sep 4 at 17:47
@EricDuminil Any decent partition implementation should take a predicate that allows you to specify how to partition it. Also, FWIW, C++'s
std::partition
moves true
elements before false
elements.– Justin
Sep 4 at 17:57
@EricDuminil Any decent partition implementation should take a predicate that allows you to specify how to partition it. Also, FWIW, C++'s
std::partition
moves true
elements before false
elements.– Justin
Sep 4 at 17:57
@Justin: Please ignore my last comment then. I learned something today.
– Eric Duminil
Sep 4 at 18:20
@Justin: Please ignore my last comment then. I learned something today.
– Eric Duminil
Sep 4 at 18:20
 |Â
show 4 more comments
up vote
5
down vote
Your code works correctly under the assumption that the given list
contains only True
or False
elements. For other lists it can return
“false positivesâ€Â
>>> check_true_then_false([1, 1, 0])
True
or abort with a runtime error:
>>> check_true_then_false(["a", "b"])
TypeError: unsupported operand type(s) for +: 'int' and 'str'
The function traverses the given list in order to find the number ofTrue
elements. It then creates two additional lists, which are also
traversed to check if all elements are True
resp. False
.
A more efficient way would be to iterate the given list only once:
- Find the first non-
True
element. If there is any then it must beFalse
. - Then find the next non-
False
element. There should not be any.
If either of the above iterations fails (and next()
raises aStopIteration
exception) then the list is of the required form, and
the function returns True
:
def check_true_then_false(x):
list_iter = iter(x)
try:
return (next(elem for elem in list_iter if elem is not True) is False
and next(elem for elem in list_iter if elem is not False) is False)
except StopIteration:
return True
Peilonrayz explained how to document the
function using docstrings. In addition, the test cases can also be
embedded into the docstrings, with doctest
:
def check_true_then_false(x):
"""Check first n values are True and the rest are False.
>>> check_true_then_false([True])
True
>>> check_true_then_false([False])
True
>>> check_true_then_false([False, True])
False
>>> check_true_then_false([True, False, True])
False
>>> check_true_then_false([1, 1, 0])
False
>>> check_true_then_false(["a", "b"])
False
"""
# ... Your code ...
if __name__ == "__main__":
import doctest
doctest.testmod()
This doesn’t correctly detect non-boolean values if the first non-True argument is not False. For example:check_true_then_false([True, True, "foo", False])
evaluates to True.
– Neil Roberts
Sep 4 at 10:21
@NeilRoberts: You are right (becausenext()
consumes that element). It should be fixed now (but lacks the elegance of Peilonrayz's solution).
– Martin R
Sep 4 at 11:01
add a comment |Â
up vote
5
down vote
Your code works correctly under the assumption that the given list
contains only True
or False
elements. For other lists it can return
“false positivesâ€Â
>>> check_true_then_false([1, 1, 0])
True
or abort with a runtime error:
>>> check_true_then_false(["a", "b"])
TypeError: unsupported operand type(s) for +: 'int' and 'str'
The function traverses the given list in order to find the number ofTrue
elements. It then creates two additional lists, which are also
traversed to check if all elements are True
resp. False
.
A more efficient way would be to iterate the given list only once:
- Find the first non-
True
element. If there is any then it must beFalse
. - Then find the next non-
False
element. There should not be any.
If either of the above iterations fails (and next()
raises aStopIteration
exception) then the list is of the required form, and
the function returns True
:
def check_true_then_false(x):
list_iter = iter(x)
try:
return (next(elem for elem in list_iter if elem is not True) is False
and next(elem for elem in list_iter if elem is not False) is False)
except StopIteration:
return True
Peilonrayz explained how to document the
function using docstrings. In addition, the test cases can also be
embedded into the docstrings, with doctest
:
def check_true_then_false(x):
"""Check first n values are True and the rest are False.
>>> check_true_then_false([True])
True
>>> check_true_then_false([False])
True
>>> check_true_then_false([False, True])
False
>>> check_true_then_false([True, False, True])
False
>>> check_true_then_false([1, 1, 0])
False
>>> check_true_then_false(["a", "b"])
False
"""
# ... Your code ...
if __name__ == "__main__":
import doctest
doctest.testmod()
This doesn’t correctly detect non-boolean values if the first non-True argument is not False. For example:check_true_then_false([True, True, "foo", False])
evaluates to True.
– Neil Roberts
Sep 4 at 10:21
@NeilRoberts: You are right (becausenext()
consumes that element). It should be fixed now (but lacks the elegance of Peilonrayz's solution).
– Martin R
Sep 4 at 11:01
add a comment |Â
up vote
5
down vote
up vote
5
down vote
Your code works correctly under the assumption that the given list
contains only True
or False
elements. For other lists it can return
“false positivesâ€Â
>>> check_true_then_false([1, 1, 0])
True
or abort with a runtime error:
>>> check_true_then_false(["a", "b"])
TypeError: unsupported operand type(s) for +: 'int' and 'str'
The function traverses the given list in order to find the number ofTrue
elements. It then creates two additional lists, which are also
traversed to check if all elements are True
resp. False
.
A more efficient way would be to iterate the given list only once:
- Find the first non-
True
element. If there is any then it must beFalse
. - Then find the next non-
False
element. There should not be any.
If either of the above iterations fails (and next()
raises aStopIteration
exception) then the list is of the required form, and
the function returns True
:
def check_true_then_false(x):
list_iter = iter(x)
try:
return (next(elem for elem in list_iter if elem is not True) is False
and next(elem for elem in list_iter if elem is not False) is False)
except StopIteration:
return True
Peilonrayz explained how to document the
function using docstrings. In addition, the test cases can also be
embedded into the docstrings, with doctest
:
def check_true_then_false(x):
"""Check first n values are True and the rest are False.
>>> check_true_then_false([True])
True
>>> check_true_then_false([False])
True
>>> check_true_then_false([False, True])
False
>>> check_true_then_false([True, False, True])
False
>>> check_true_then_false([1, 1, 0])
False
>>> check_true_then_false(["a", "b"])
False
"""
# ... Your code ...
if __name__ == "__main__":
import doctest
doctest.testmod()
Your code works correctly under the assumption that the given list
contains only True
or False
elements. For other lists it can return
“false positivesâ€Â
>>> check_true_then_false([1, 1, 0])
True
or abort with a runtime error:
>>> check_true_then_false(["a", "b"])
TypeError: unsupported operand type(s) for +: 'int' and 'str'
The function traverses the given list in order to find the number ofTrue
elements. It then creates two additional lists, which are also
traversed to check if all elements are True
resp. False
.
A more efficient way would be to iterate the given list only once:
- Find the first non-
True
element. If there is any then it must beFalse
. - Then find the next non-
False
element. There should not be any.
If either of the above iterations fails (and next()
raises aStopIteration
exception) then the list is of the required form, and
the function returns True
:
def check_true_then_false(x):
list_iter = iter(x)
try:
return (next(elem for elem in list_iter if elem is not True) is False
and next(elem for elem in list_iter if elem is not False) is False)
except StopIteration:
return True
Peilonrayz explained how to document the
function using docstrings. In addition, the test cases can also be
embedded into the docstrings, with doctest
:
def check_true_then_false(x):
"""Check first n values are True and the rest are False.
>>> check_true_then_false([True])
True
>>> check_true_then_false([False])
True
>>> check_true_then_false([False, True])
False
>>> check_true_then_false([True, False, True])
False
>>> check_true_then_false([1, 1, 0])
False
>>> check_true_then_false(["a", "b"])
False
"""
# ... Your code ...
if __name__ == "__main__":
import doctest
doctest.testmod()
edited Sep 4 at 10:59
answered Sep 4 at 8:26


Martin R
14.6k12258
14.6k12258
This doesn’t correctly detect non-boolean values if the first non-True argument is not False. For example:check_true_then_false([True, True, "foo", False])
evaluates to True.
– Neil Roberts
Sep 4 at 10:21
@NeilRoberts: You are right (becausenext()
consumes that element). It should be fixed now (but lacks the elegance of Peilonrayz's solution).
– Martin R
Sep 4 at 11:01
add a comment |Â
This doesn’t correctly detect non-boolean values if the first non-True argument is not False. For example:check_true_then_false([True, True, "foo", False])
evaluates to True.
– Neil Roberts
Sep 4 at 10:21
@NeilRoberts: You are right (becausenext()
consumes that element). It should be fixed now (but lacks the elegance of Peilonrayz's solution).
– Martin R
Sep 4 at 11:01
This doesn’t correctly detect non-boolean values if the first non-True argument is not False. For example:
check_true_then_false([True, True, "foo", False])
evaluates to True.– Neil Roberts
Sep 4 at 10:21
This doesn’t correctly detect non-boolean values if the first non-True argument is not False. For example:
check_true_then_false([True, True, "foo", False])
evaluates to True.– Neil Roberts
Sep 4 at 10:21
@NeilRoberts: You are right (because
next()
consumes that element). It should be fixed now (but lacks the elegance of Peilonrayz's solution).– Martin R
Sep 4 at 11:01
@NeilRoberts: You are right (because
next()
consumes that element). It should be fixed now (but lacks the elegance of Peilonrayz's solution).– Martin R
Sep 4 at 11:01
add a comment |Â
up vote
1
down vote
You can make this more efficient by using a simple loop:
def check_true_then_false(x):
prev = True
for i in x:
current = bool(i)
if current and not prev:
# Found truthy element after falsy one.
return False
prev = current
return True
Tested here
This requires one full iteration and negligible memory in the worst case, while your solution requires 5 iterations (4 plus 1 over each of the split lists) and two lists that sum to the length of the original (somewhere on the order of double the memory).
Explicitly written out loops are often remarkably slow in Python, compared to the built in list handling functions; so much so that I wouldn't be comfortable betting that this is faster without a profiler. Nevertheless this is certainly more memory efficient than the original, is easy to read, is clear why it does what it claims including where it's an improvement on the original code. Overall I would definitely take something like this as a first implementation and then look for built in functions that replicate it to optimise.
– Josiah
Sep 5 at 7:24
add a comment |Â
up vote
1
down vote
You can make this more efficient by using a simple loop:
def check_true_then_false(x):
prev = True
for i in x:
current = bool(i)
if current and not prev:
# Found truthy element after falsy one.
return False
prev = current
return True
Tested here
This requires one full iteration and negligible memory in the worst case, while your solution requires 5 iterations (4 plus 1 over each of the split lists) and two lists that sum to the length of the original (somewhere on the order of double the memory).
Explicitly written out loops are often remarkably slow in Python, compared to the built in list handling functions; so much so that I wouldn't be comfortable betting that this is faster without a profiler. Nevertheless this is certainly more memory efficient than the original, is easy to read, is clear why it does what it claims including where it's an improvement on the original code. Overall I would definitely take something like this as a first implementation and then look for built in functions that replicate it to optimise.
– Josiah
Sep 5 at 7:24
add a comment |Â
up vote
1
down vote
up vote
1
down vote
You can make this more efficient by using a simple loop:
def check_true_then_false(x):
prev = True
for i in x:
current = bool(i)
if current and not prev:
# Found truthy element after falsy one.
return False
prev = current
return True
Tested here
This requires one full iteration and negligible memory in the worst case, while your solution requires 5 iterations (4 plus 1 over each of the split lists) and two lists that sum to the length of the original (somewhere on the order of double the memory).
You can make this more efficient by using a simple loop:
def check_true_then_false(x):
prev = True
for i in x:
current = bool(i)
if current and not prev:
# Found truthy element after falsy one.
return False
prev = current
return True
Tested here
This requires one full iteration and negligible memory in the worst case, while your solution requires 5 iterations (4 plus 1 over each of the split lists) and two lists that sum to the length of the original (somewhere on the order of double the memory).
answered Sep 5 at 0:15


jpmc26
51127
51127
Explicitly written out loops are often remarkably slow in Python, compared to the built in list handling functions; so much so that I wouldn't be comfortable betting that this is faster without a profiler. Nevertheless this is certainly more memory efficient than the original, is easy to read, is clear why it does what it claims including where it's an improvement on the original code. Overall I would definitely take something like this as a first implementation and then look for built in functions that replicate it to optimise.
– Josiah
Sep 5 at 7:24
add a comment |Â
Explicitly written out loops are often remarkably slow in Python, compared to the built in list handling functions; so much so that I wouldn't be comfortable betting that this is faster without a profiler. Nevertheless this is certainly more memory efficient than the original, is easy to read, is clear why it does what it claims including where it's an improvement on the original code. Overall I would definitely take something like this as a first implementation and then look for built in functions that replicate it to optimise.
– Josiah
Sep 5 at 7:24
Explicitly written out loops are often remarkably slow in Python, compared to the built in list handling functions; so much so that I wouldn't be comfortable betting that this is faster without a profiler. Nevertheless this is certainly more memory efficient than the original, is easy to read, is clear why it does what it claims including where it's an improvement on the original code. Overall I would definitely take something like this as a first implementation and then look for built in functions that replicate it to optimise.
– Josiah
Sep 5 at 7:24
Explicitly written out loops are often remarkably slow in Python, compared to the built in list handling functions; so much so that I wouldn't be comfortable betting that this is faster without a profiler. Nevertheless this is certainly more memory efficient than the original, is easy to read, is clear why it does what it claims including where it's an improvement on the original code. Overall I would definitely take something like this as a first implementation and then look for built in functions that replicate it to optimise.
– Josiah
Sep 5 at 7:24
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f203068%2ffunction-to-check-that-a-python-list-contains-only-true-and-then-only-false%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sorry it didn't work out. Try again on SO. I have a concrete answer I'd like to post that I think would work for this site, but would also work for SO.
– Mad Physicist
Sep 4 at 3:41
Ping me if you decide to make the post again.
– Mad Physicist
Sep 4 at 3:42
1
I've just removed this question from SO because I was told it was better suited to Code Review, so I don't know where to post it anymore.
– Hasnep
Sep 4 at 3:51
5
Could you clarify the requirements? Are
,
[True]
, and[False, False]
acceptable?– 200_success
Sep 4 at 10:06
1
Another way of explaining is any list that can we written as
[True] * n + [False] * m
forn
,m
integers in the interval [0, infty).– Hasnep
Sep 5 at 2:18