Function to check that a Python list contains only True and then only False

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
8
down vote

favorite
1












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]






share|improve this question






















  • 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 for n, m integers in the interval [0, infty).
    – Hasnep
    Sep 5 at 2:18

















up vote
8
down vote

favorite
1












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]






share|improve this question






















  • 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 for n, m integers in the interval [0, infty).
    – Hasnep
    Sep 5 at 2:18













up vote
8
down vote

favorite
1









up vote
8
down vote

favorite
1






1





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]






share|improve this question














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]








share|improve this question













share|improve this question




share|improve this question








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 for n, 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










  • 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 for n, 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











4 Answers
4






active

oldest

votes

















up vote
13
down vote



accepted










  • 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:



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





share|improve this answer


















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






  • 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










  • @MathiasEttinger Yeah, that's probably a better way to describe it :)
    – Peilonrayz
    Sep 4 at 19:45

















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]





share|improve this answer
















  • 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 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 : Trues should appear before Falses.
    – 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










  • @Justin: Please ignore my last comment then. I learned something today.
    – Eric Duminil
    Sep 4 at 18:20

















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 of
True 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 be False.

  • Then find the next non-False element. There should not be any.

If either of the above iterations fails (and next() raises a
StopIteration 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()





share|improve this answer






















  • 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

















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






share|improve this answer




















  • 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










Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













 

draft saved


draft discarded


















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






























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



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





share|improve this answer


















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






  • 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










  • @MathiasEttinger Yeah, that's probably a better way to describe it :)
    – Peilonrayz
    Sep 4 at 19:45














up vote
13
down vote



accepted










  • 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:



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





share|improve this answer


















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






  • 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










  • @MathiasEttinger Yeah, that's probably a better way to describe it :)
    – Peilonrayz
    Sep 4 at 19:45












up vote
13
down vote



accepted







up vote
13
down vote



accepted






  • 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:



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





share|improve this answer














  • 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:



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






share|improve this answer














share|improve this answer



share|improve this answer








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






  • 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










  • @MathiasEttinger Yeah, that's probably a better way to describe it :)
    – Peilonrayz
    Sep 4 at 19:45












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






  • 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










  • @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












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]





share|improve this answer
















  • 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 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 : Trues should appear before Falses.
    – 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










  • @Justin: Please ignore my last comment then. I learned something today.
    – Eric Duminil
    Sep 4 at 18:20














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]





share|improve this answer
















  • 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 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 : Trues should appear before Falses.
    – 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










  • @Justin: Please ignore my last comment then. I learned something today.
    – Eric Duminil
    Sep 4 at 18:20












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]





share|improve this answer












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]






share|improve this answer












share|improve this answer



share|improve this answer










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 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 : Trues should appear before Falses.
    – 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










  • @Justin: Please ignore my last comment then. I learned something today.
    – Eric Duminil
    Sep 4 at 18:20












  • 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 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 : Trues should appear before Falses.
    – 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










  • @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 : Trues should appear before Falses.
– 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 : Trues should appear before Falses.
– 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










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 of
True 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 be False.

  • Then find the next non-False element. There should not be any.

If either of the above iterations fails (and next() raises a
StopIteration 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()





share|improve this answer






















  • 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














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 of
True 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 be False.

  • Then find the next non-False element. There should not be any.

If either of the above iterations fails (and next() raises a
StopIteration 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()





share|improve this answer






















  • 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












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 of
True 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 be False.

  • Then find the next non-False element. There should not be any.

If either of the above iterations fails (and next() raises a
StopIteration 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()





share|improve this answer














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 of
True 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 be False.

  • Then find the next non-False element. There should not be any.

If either of the above iterations fails (and next() raises a
StopIteration 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()






share|improve this answer














share|improve this answer



share|improve this answer








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
















  • 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















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










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






share|improve this answer




















  • 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














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






share|improve this answer




















  • 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












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






share|improve this answer












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







share|improve this answer












share|improve this answer



share|improve this answer










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
















  • 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

















 

draft saved


draft discarded















































 


draft saved


draft discarded














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













































































Comments

Popular posts from this blog

What does second last employer means? [closed]

List of Gilmore Girls characters

Confectionery