为啥这个涉及 list.index() 调用的 lambda 这么慢?

Posted

技术标签:

【中文标题】为啥这个涉及 list.index() 调用的 lambda 这么慢?【英文标题】:Why is this lambda involving a list.index() call so slow?为什么这个涉及 list.index() 调用的 lambda 这么慢? 【发布时间】:2014-10-30 02:36:33 【问题描述】:

使用 cProfile:

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000   17.834   17.834 <string>:1(<module>)
        1    0.007    0.007   17.834   17.834 basher.py:5551(_refresh)
        1    0.000    0.000   10.522   10.522 basher.py:1826(RefreshUI)
        4    0.024    0.006   10.517    2.629 basher.py:961(PopulateItems)
      211    1.494    0.007    7.488    0.035 basher.py:1849(PopulateItem)
      231    0.074    0.000    6.734    0.029 method 'sort' of 'list' objects
      215    0.002    0.000    6.688    0.031 bosh.py:4764(getOrdered)
     1910    3.039    0.002    6.648    0.003 bosh.py:4770(<lambda>)
      253    0.178    0.001    5.600    0.022 bosh.py:3325(getStatus)
        1    0.000    0.000    5.508    5.508 bosh.py:4327(refresh)
     1911    3.051    0.002    3.330    0.002 method 'index' of 'list' objects

1910 3.039 0.002 6.648 0.003 bosh.py:4770(&lt;lambda&gt;) 行让我很困惑。在 bosh.py:4770 我有 modNames.sort(key=lambda a: (a in data) and data.index(a)),数据和 modNames 是列表。注意1911 3.051 0.002 3.330 0.002 method 'index' of 'list' objects,它似乎来自这条线。

那么为什么这么慢呢?有什么办法可以重写这个sort(),让它运行得更快?

编辑:我缺少了解这个 lambda 的最后一种成分:

>>> True and 3
3

【问题讨论】:

函数体是a in data and data.index(a),其中的两个操作是O(n),其中n是数据的列表大小。如果不回答你的整个问题,我会把责任归咎于这个 lambda 函数。每次调用时,lambda 都会扫描data。如果你对data 使用字典而不是列表,它可能会更快,因为字典的平均查找时间复杂度为 O(1)。 【参考方案1】:

正如 YardGlassOfCode 所说,不是 lambda 本身很慢,而是 lambda 内部的 O(n) 操作很慢。 a in datadata.index(a) 都是O(n) operations,其中ndata 的长度。作为对效率的额外侮辱,对index 的调用也重复了a in data 中完成的大部分工作。如果data 中的项目是可散列的,那么您可以通过首先准备一个字典来大大加快速度:

weight = dict(zip(data, range(len(data))))
modNames.sort(key=weight.get)  # Python2, or
modNames.sort(key=lambda a: weight.get(a, -1))  # works in Python3

这要快得多,因为each dict lookup is a O(1) operation。

请注意,modNames.sort(key=weight.get) 依赖于 None 比较小于整数:

In [39]: None < 0
Out[39]: True

在 Python3 中,None &lt; 0 引发 TypeError。所以lambda a: weight.get(a, -1) 用于在a 不在weight 中时返回-1。

【讨论】:

谢谢 - 将对其进行测试并回复。所以我也猜想原来的工作是因为False &lt; 0 也(sort(key=...) 可以使用一些文档) Since False == 0False &lt; 0 为 False,0 &lt; False 为 False。这意味着在原始项目中,索引为 0 的项目可能会夹在不在 data 中的项目之间。例如,考虑sorted([False, 0, False]) 注意:我使用了key=lambda a: dataDict.get(a, sys.maxint),因为我希望将不存在的项目订购到底部 python 2.7.8

以上是关于为啥这个涉及 list.index() 调用的 lambda 这么慢?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 C# HttpClient 不能调用这个 URL(总是超时)?

为啥这个 stl 函数调用会导致不正确的布尔评估? [复制]

为啥在VC++6.0下用C语言调用引用参数如:void Creat(SqList &L)总是提示&出错?

为啥“echo l > /proc/sysrq-trigger”调用跟踪输出总是相似?

如何查找相同项目的列表索引[重复]

为啥这个涉及 floor 函数的公式没有给出我期望的结果?