检查列表的大多数Python方法可以归结为一个值



我想要一个函数check来检查给定的list在给定的函数reduce_function下是否精确地减少("归结"(为一个值。(一个常见的例子是检查列表列表是否只包含长度相等的子列表。(

我认为至少有以下三种方法可以实现这一点。对于他们每一个人,我都看到了一些优点和缺点。在我看来,它们都不太可读。你能给我一个详细的概述吗:

哪一个会被认为是最可读、最"蟒蛇"的

1.测量一组缩减值的长度

这似乎是最可读的,但需要reduce_function返回一个散列表:

def check(lst):
return len(set(map(reduce_function, lst))) == 1

2.统计组数

def check(lst):
return len(list(itertools.groupby(lst, key=reduce_function)) == 1

3.与第一个元素比较时使用all

这需要一个额外的or-语句(可以用if-else-语句代替(来覆盖lst为空的情况。

def check(lst):
return not lst or all([reduce_function(el) == reduce_function(lst[0]) for el in lst])

我喜欢所有三个选项,尽管第三个不需要列表理解,只需去掉方括号即可。

与您的第二个选项一样,itertools文档有一个名为all_equal的配方,它也使用itertools.groupby来检查可迭代文件中的所有元素是否相等,尽管它们没有考虑自定义函数,并且在为空时默认为false,但它可以很容易地实现:

def all_equal(iterable, key=reduce_function):
g = groupby(iterable, key)
return next(g, False) and not next(g, False)

itertools.all_equal是检查迭代中所有元素是否相等的"Python"方法;我只是根据你的需要修改了它。

这可能有点基于观点,但也有客观原因支持或反对不同的替代方案。我将在这里集中讨论第一个和第三个。

第一种方法,转换为set并测试其长度,是IMHO最干净的,但它有O(n(额外的空间要求(在所有元素相同的最坏情况下(。它也适用于任何可迭代项,而第三个仅适用于lst实际上是list的情况在其当前形式中,第三种方法也具有O(n(空间复杂性,(在所有的情况下(,这是由于all中的列表理解[...];您可以改用生成器表达式。此外,针对每个其它元素重新计算reduce_function(lst[0])。最后,not lst or是冗余的,因为空列表的allTrue

此外,请注意,如果您想测试列表是否"归结"为最多一个值,如not lst or所暗示的,则应检查len(...) <= 1中的前两种方法。


我没有测试这一点,但我认为这应该有效,a(使用不可哈希的reduce_function,b(是O(1(空间复杂性,c(使用列表或可迭代,d(尊重空列表角的情况:

def check(lst):
return sum(1 for _ in itertools.groupby(lst, key=reduce_function)) <= 1

尽管已经很清楚存在不止一个不同的值,但这仍然会对整个lstreduce_function进行评估。

如果你想检查是否所有的值都可以减少到相同的值,你不需要浏览整个列表。一旦发现一个值不等于列表中的第一个元素,就可以立即停止。它将更有效率:

def check(func, lst):
it = iter(lst)
first = func(next(it))
for i in it:
if func(i) != first:
return False
return True

您也可以用函数all替换for循环。在使用all的解决方案中,您计算列表中的第一个元素len(lst) + 1次。

def check(func, lst):
it = iter(lst)
first = func(next(it))
return all(first == func(i) for i in it)
check(sum, [[0, 1], [0, 1], [0, 1]])
# True
check(sum, [[1, 1], [0, 1], [0, 1]])
# False

最新更新