如何使用一两行检查Python列表仅包含True,然后仅包含False?

时间:2018-09-04 02:31:54

标签: python python-3.x

我只允许列表中第一个连续的元素组为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]

是否可以使用理解来使它成为一两行功能?我知道我无法定义这两个临时列表,而是将它们的定义放在返回行上,以代替它们的名称,但是我认为那太乱了。

1 个答案:

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

您也可以直接使用迭代器一次完成此操作。这取决于anyallguaranteed 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