繁体   English   中英

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

[英]Most pythonic way to check list boils down to one value

我想要一个 function check来检查给定list是否减少(“归结”)到给定 function reduce_function下的一个值。 (一个常见的例子可能是检查列表列表是否仅包含相等长度的子列表。)

我至少看到了以下三种方法来实现这一点。 对于他们每个人,我都看到了一些优点和缺点。 在我看来,它们中的任何一个都没有真正的可读性。 你能给我一个详细的概述:

哪一个会被认为是最具可读性和最“pythonic”的?

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

我喜欢所有 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

尽管如此,这仍然会评估整个lstreduce_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM