列表中最长单词的长度

7 投票
6 回答
16983 浏览
提问于 2025-04-17 14:23

获取最长单词长度的更“Python风格”的方法是什么呢:

len(max(words, key=len))

还是:

max(len(w) for w in words)

或者..其他方法?words 是一个字符串列表。

我发现我经常需要做这个操作,经过对几个不同样本大小的测试,第一种方法似乎一直更快,尽管乍一看似乎不太高效(因为len被调用了两次,看起来有点多余,但这似乎并不影响 - 这种形式下在C代码中会发生更多事情吗?)

6 个回答

4

如果你把生成器表达式改成用 map 函数来写(在 Python 2.x 中用 imap),

max(map(len, words))

… 其实这样比用键的版本要快一点,并不是更慢。

在 python.org 的 64 位 3.3.0 版本上:

In [186]: words = ['now', 'is', 'the', 'winter', 'of', 'our', 'partyhat'] * 100
In [188]: %timeit max(len(w) for w in words)
%10000 loops, best of 3: 90.1 us per loop
In [189]: %timeit len(max(words, key=len))
10000 loops, best of 3: 57.3 us per loop
In [190]: %timeit max(map(len, words))
10000 loops, best of 3: 53.4 us per loop

在 Apple 的 64 位 2.7.2 版本上:

In [298]: words = ['now', 'is', 'the', 'winter', 'of', 'our', 'partyhat'] * 100
In [299]: %timeit max(len(w) for w in words)
10000 loops, best of 3: 99 us per loop
In [300]: %timeit len(max(words, key=len))
10000 loops, best of 3: 64.1 us per loop
In [301]: %timeit max(map(len, words))
10000 loops, best of 3: 67 us per loop
In [303]: %timeit max(itertools.imap(len, words))
10000 loops, best of 3: 63.4 us per loop

我觉得这样写比用 key 的版本更符合 Python 的风格,原因和生成器表达式一样。

至于它是否和生成器表达式一样符合 Python 风格,这个可以争论。有些人喜欢 mapfilterreduce 等;有些人则不喜欢;我个人觉得,当你想用一个已经存在并且名字好听的函数时(也就是说,不需要用 lambdapartial 来处理),用 map 会更好,不过这也因人而异(特别是如果你叫 Guido 的话)。

最后一点:

调用 len 两次的冗余似乎没什么关系——在这种情况下,C 代码会做更多的事情吗?

可以这样想:你已经调用了 len N 次。如果改成调用 N+1 次,和你需要做的 N 次相比,几乎不会有什么区别,除非你有一些 极小超大 字符串。

8

虽然:

max(len(w) for w in words)

看起来“读起来”更简单一些,但使用生成器会增加一些额外的开销。

而:

len(max(words, key=len))

可以利用内置函数进行优化,而且因为 len 通常对字符串来说是一个非常高效的操作,所以会更快……

5

我觉得这两种写法都可以,但如果不考虑速度的话,max(len(w) for w in words) 这段代码看起来更容易理解。

当我在看这两种写法时,花了我更长的时间去搞明白 len(max(words, key=len)) 是在干嘛,直到我多想了一会儿才明白,之前的理解还是错的。代码应该一眼就能看懂,除非有特别的理由让它变得复杂。

从其他人的帖子和我自己的测试来看,那个不太容易理解的写法确实更快。但其实两者的速度都还不错,并不是特别慢。除非这段代码在关键路径上,否则没必要太担心速度问题。

总的来说,我觉得更容易理解的写法更符合 Python 的风格。

顺便提一下,这是少数几个 Python 2 在同样任务上明显比 Python 3 快的情况之一。

撰写回答