我只允许列表中第一个连续的元素组为True
,然后所有其余元素为False
。我希望像这些示例一样的列表返回True
:
[True]
[False]
[True, False]
[True, False, False]
[True, True, True, False]
并且类似这样的列表返回False
:
[False, True]
[True, False, True]
我当前正在使用此功能,但我觉得可能有更好的方法:
def my_function(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 all([not element for element in should_be_false])
测试:
test_cases = [[True], [False],
[True, False],
[True, False, False],
[True, True, True, False],
[False, True],
[True, False, True]]
print([my_function(test_case) for test_case in test_cases])
# expected output: [True, True, True, True, True, False, False]
是否可以使用理解来使它成为一两行功能?我知道我无法定义这两个临时列表,而是将它们的定义放在返回行上,以代替它们的名称,但是我认为那太乱了。
答案 0 :(得分:2)
方法1
您可以使用itertools.groupby
。这样可以避免对列表进行多次遍历,也可以避免首先创建临时列表:
def check(x):
status = list(k for k, g in groupby(x))
return len(status) <= 2 and (status[0] is True or status[-1] is False)
这假定您的输入为非空且已经为布尔值。如果并非总是如此,请进行相应调整:
def check(x):
status = list(k for k, g in groupby(map(book, x)))
return status and len(status) <= 2 and (status[0] or not status[-1])
如果您希望将空数组的值评估为True,请特殊处理,或者使最后一行复杂一些:
return not status or (len(status) <= 2 and (status[0] or not status[-1]))
方法2
您也可以直接使用迭代器一次完成此操作。这取决于any
和all
为guaranteed to short-circuit的事实:
def check(x):
iterator = iter(x)
# process the true elements
all(iterator)
# check that there are no true elements left
return not any(iterator)
就我个人而言,我认为方法1是彻底的过度杀伤。方法2更好,更简单,并且可以更快地实现相同的目标。如果测试失败,它也会立即停止,而不必处理整个组。它也根本不分配任何临时列表,即使对于组聚合也是如此。最后,它可以立即处理空的和非布尔的输入。
自从我在移动设备上写书以来,这是一个IDEOne验证链接:https://ideone.com/4MAYYa