[英]Most Pythonic way to find/check items in a list with O(1) complexity?
[英]Most pythonic way to check list boils down to one value
我想要一个 function check
来检查给定list
是否减少(“归结”)到给定 function reduce_function
下的一个值。 (一个常见的例子可能是检查列表列表是否仅包含相等长度的子列表。)
我至少看到了以下三种方法来实现这一点。 对于他们每个人,我都看到了一些优点和缺点。 在我看来,它们中的任何一个都没有真正的可读性。 你能给我一个详细的概述:
哪一个会被认为是最具可读性和最“pythonic”的?
这似乎最易读,但需要reduce_function
返回一个哈希值:
def check(lst):
return len(set(map(reduce_function, lst))) == 1
def check(lst):
return len(list(itertools.groupby(lst, key=reduce_function)) == 1
all
与第一个元素进行比较这需要一个额外的or
- 语句(可以用if
- else
- 语句代替)来覆盖lst
为空的情况。
def check(lst):
return not lst or all([reduce_function(el) == reduce_function(lst[0]) for el in lst])
我喜欢所有 3 个选项,尽管第三个不需要是列表理解,只需去掉方括号即可。
与您的第二个选项一样, itertools
文档有一个名为all_equal
的配方,它也使用itertools.groupby
检查可迭代对象中的所有元素是否相等,尽管它们没有考虑自定义 function 并且在为空时默认为 false 但它很容易实施的:
def all_equal(iterable, key=reduce_function):
g = groupby(iterable, key)
return next(g, False) and not next(g, False)
itertools.all_equal
是检查迭代中所有元素是否相等的“pythonic”方法; 我只是修改它以满足您的需求。
这可能有点基于意见,但也有客观原因支持或反对不同的选择。 我将在这里重点介绍第一个和第三个。
第一种方法,转换为一个set
并测试它的长度,恕我直言,它是最干净的,但它有 O(n) 额外的空间要求(在所有元素不相同的最坏情况下)。 它也适用于任何可迭代对象,而第三个仅适用于lst
实际上是list
。 在当前的形式中,第三种方法也具有 O(n) 空间复杂度,(在所有情况下)由于列表理解[...]
all
; 您可以改用生成器表达式。 此外, reduce_function(lst[0])
为每个其他元素重新计算。 最后, not lst or
是多余的,因为all
空列表都是True
。
另外,请注意,如果您想测试列表是否“归结”为最多一个值,正如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
尽管如此,这仍然会评估整个lst
的reduce_function
,即使已经很清楚存在多个不同的值。
如果要检查是否所有值都可以减少到相同的值,则不需要通过整个列表 go。 一旦发现不等于列表中第一个元素的值,您就可以停止。 它会更有效率:
def check(func, lst):
it = iter(lst)
first = func(next(it))
for i in it:
if func(i) != first:
return False
return True
您也可以用 function 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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.