检查列表中所有列表长度是否相同的更好方法是什么?

18

当前正在运行:

l1 = [i for i in range(0,10)]
l2 = [i for i in range(0,10)]
l3 = [i for i in range(0,10)]
lists = [l1, l2, l3]
length = len(lists[0])
for l in lists:
    if length != len(l):
        raise ValueErrorr('not all lists have same length!')

除了使用for循环,是否有更好的方法来测试这个问题?是否有更快/更好的方法,而不是O(n)?


更快/更好的方法是,如果你在第一个列表形成后计算范围值之间的差异,并将该计数用作在创建其他列表之前的前提条件。这样,你可以避免使用for循环和O(n)解决方案,因为如果其他列表的范围差异超过第一个列表的范围差异,你甚至不会创建其他列表。 - YBathia
5个回答

26

我会使用生成器表达式和all来完成它:

it = iter(lists)
the_len = len(next(it))
if not all(len(l) == the_len for l in it):
     raise ValueError('not all lists have same length!')

这样可以避免两次检查第一个列表的长度,并且不会构建用后即丢的列表/集合数据结构。

all也是惰性求值的,这意味着它会在生成器产生第一个长度不同的列表时停止并返回False


如果列表为空,则返回True。 - jfs

11

您可以使用集合推导式来保留唯一长度,然后检查集合中是否只有一个元素:

if len({len(i) for i in lists}) == 1:
    # do stuff

或者更有效的方法是在 anyall 中使用生成器表达式。

def check_size_eq(lst):
    # returns true if there's any list with unequal length to the first one
    return not any(len(lst[0])!= len(i) for i in lst)
    # or you could do:
    # return all(len(lst[0])== len(i) for i in lst)

演示:

>>> a = {1}
>>> 
>>> a.pop() and not a
True
>>> a = {1,3}
>>> a.pop() and not a
False

1
第一个看起来非常漂亮,但是它会一直循环整个列表吗? - deepbrook
@j4ck 是的,第一种方法更符合 Python 的风格。但你所说的“它不总是要遍历整个列表”的意思是什么?我认为这正是它应该做的。 - Mazdak
3
我的意思是,它不会在第一个len()不同的情况下退出,对吧?因此,最坏和最好情况都是O(n)? - deepbrook
1
@j4ck 啊,没错,从算法的角度来看,你说得完全正确。在这种情况下,timgeb的答案是最好的(或者可以使用any()实现)。 - Mazdak
感谢您澄清这个问题 :) - deepbrook

6
你可以使用map函数来获取列表的长度(在Python3中,这将是一个迭代器)。
lengths = map(len,lists)

然后,您可以将此应用于set函数,将其转换为独特值的集合。如果只有一个值,则它们长度相同。

if len(set(map(len,lists)))==1:
    print("All are the same length")
else:
    print("They are not the same length!")

4

首先,你的解决方案不是O(logn)。也不能有对数算法。你至少需要检查每个项目一次,因此O(n)是最优复杂度。

#  import imap from itertools on Py2


if len(set(map(len, lists))) not in (0, 1):
    raise ValueErrorr('not all lists have same length!')

你说得对,它不是O(1) - 我的意思是O(n);已经修正了。 - deepbrook
同样的问题也适用于你 - 那样不是总会强制它遍历整个列表吗?我明白我的最坏情况是O(n),但你的最好情况也不是O(n)吗? - deepbrook
1
@j4ck 是的,这确实会遍历整个数组。如果你想要提前退出,请使用 all(尽管它仍然具有较小的常数的 O(n))。 - Eli Korvigo
使用<= 1代替!= 1。没有列表(len(lists) == 0)意味着没有长度不同的列表。 - jfs
@J.F.Sebastian 很详细,谢谢。 - Eli Korvigo

1
定义“更好的方式”因人而异,这个看起来很时尚,但不像Python代码应该那样易于理解。
lists_are_length_equaled = False not in [len(i) == len(lists[0]) for i in lists]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接