[英]Most pythonic way to check list boils down to one value
I want a function check
to check that a given list
reduces ("boils down") to exactly one value under a given function reduce_function
.我想要一个 function
check
来检查给定list
是否减少(“归结”)到给定 function reduce_function
下的一个值。 (A common example could be to check that a list of lists contains sublists of equal length only.) (一个常见的例子可能是检查列表列表是否仅包含相等长度的子列表。)
I see at least the three following ways to achieve this.我至少看到了以下三种方法来实现这一点。 For each of them, I see some advantages and disadvantages.
对于他们每个人,我都看到了一些优点和缺点。 None of them really looks very readable to my eye.
在我看来,它们中的任何一个都没有真正的可读性。 Could you give me an elaborate overview about:
你能给我一个详细的概述:
Which one would be considered most readable and most "pythonic"?哪一个会被认为是最具可读性和最“pythonic”的?
This seems most readable, but requires reduce_function
to return a hashable:这似乎最易读,但需要
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
on comparison with first element all
与第一个元素进行比较This needs an additional or
-statement (which could be replaced by an if
- else
-statement) to cover the case of lst
being empty.这需要一个额外的
or
- 语句(可以用if
- else
- 语句代替)来覆盖lst
为空的情况。
def check(lst):
return not lst or all([reduce_function(el) == reduce_function(lst[0]) for el in lst])
I like all 3 options although the third doesn't need to be a list comprehension, just take the square brackets off.我喜欢所有 3 个选项,尽管第三个不需要是列表理解,只需去掉方括号即可。
Like your second option the itertools
documentation has a recipe called all_equal
that checks if all elements in an iterable are equal using itertools.groupby
as well, although they didn't account for a custom function and defaulting to false when empty but it can easily be implemented:与您的第二个选项一样,
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
is the "pythonic" way to check if all elements are equal in an iterable; itertools.all_equal
是检查迭代中所有元素是否相等的“pythonic”方法; I only modified it to fit your needs.我只是修改它以满足您的需求。
This is probably a bit opinion based, but there are also objective reasons for or against the different alternatives.这可能有点基于意见,但也有客观原因支持或反对不同的选择。 I'll focus on the first and third one here.
我将在这里重点介绍第一个和第三个。
The first approach, converting to a set
and testing it's length, is IMHO the cleanest, but it has O(n) additional space requirement (in the worst case of all elements being not the same).第一种方法,转换为一个
set
并测试它的长度,恕我直言,它是最干净的,但它有 O(n) 额外的空间要求(在所有元素不相同的最坏情况下)。 It also works with any iterable, whereas the third one only works if lst
is actually a list
.它也适用于任何可迭代对象,而第三个仅适用于
lst
实际上是list
。 In it's current form the third approach also has O(n) space complexity, too, (in all cases) due to the list comprehension [...]
within the all
;在当前的形式中,第三种方法也具有 O(n) 空间复杂度,(在所有情况下)由于列表理解
[...]
all
; you can use a generator expression instead.您可以改用生成器表达式。 Further,
reduce_function(lst[0])
is recomputed for each other element.此外,
reduce_function(lst[0])
为每个其他元素重新计算。 Finally, the not lst or
is redundant, as all
of an empty list is True
.最后,
not lst or
是多余的,因为all
空列表都是True
。
Also, note that if you want to test if the list "boils down" to at most one value, as implied by the not lst or
, you should check len(...) <= 1
for the first two approaches.另外,请注意,如果您想测试列表是否“归结”为最多一个值,正如
not lst or
所暗示的那样,您应该检查前两种方法的len(...) <= 1
。
I did not test this, but I think this should work, and a) work with non-hashable reduce_function
, b) be O(1) space complexity, c) work with lists or iterables, and d) respect the empty-list corner case:我没有对此进行测试,但我认为这应该可行,并且 a) 使用不可散列的
reduce_function
,b) 是 O(1) 空间复杂度,c) 使用列表或可迭代对象,并且 d) 尊重空列表角案子:
def check(lst):
return sum(1 for _ in itertools.groupby(lst, key=reduce_function)) <= 1
This will still evaluate reduce_function
for the entire lst
, though, even if it's already clear that there is more than one distinct value.尽管如此,这仍然会评估整个
lst
的reduce_function
,即使已经很清楚存在多个不同的值。
If you want to check if all values can be reduced to the same value you don't need to go through the whole list.如果要检查是否所有值都可以减少到相同的值,则不需要通过整个列表 go。 You can stop as soon as you find a value that is not equal to the first element in the list.
一旦发现不等于列表中第一个元素的值,您就可以停止。 It will be more efficient:
它会更有效率:
def check(func, lst):
it = iter(lst)
first = func(next(it))
for i in it:
if func(i) != first:
return False
return True
You can also replace the for
loop with the function all
.您也可以用 function
all
替换for
循环。 In your solution with all
you calculate the first element in the list len(lst) + 1
times.在您的解决方案
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.