【问题标题】:Complexity analysis of filter() with a lambda function使用 lambda 函数对 filter() 进行复杂度分析
【发布时间】:2015-04-08 07:04:22
【问题描述】:

给定两个列表,list1list2

list3 = filter(lambda x: x in list1,list2)

这将返回两个列表的交集。

我怎样才能找到这个算法的复杂性?我发现x in list1 的时间复杂度是O(n) 其中n 是列表中元素的数量,但是filter 呢?

【问题讨论】:

  • 你知道如何分析计算复杂度吗?如果没有,那就去学习这样做。如果你这样做了,你在这个练习中遇到了哪些具体困难?

标签: python functional-programming time-complexity


【解决方案1】:

您的代码对元素执行O(len(list1) * len(list2)) 比较操作。

  • 您的 lambda 函数执行O(len(list2)) 次,每个过滤的元素执行一次。 See documentation for filter in Python 3(Python 2):

    filter(function, iterable)

    iterable 中函数返回 true 的那些元素构造一个 iteratoriterable 可以是序列、支持迭代的容器或迭代器

    (强调我的)

    显然,对于可迭代中的每个(不同)元素,该函数至少被调用 1 次 - 知道何时不需要调用它也意味着解决 the Halting problem in general case,甚至 Python 核心开发人员都还没有解决 ;-) .在 CPython 3 中的实践中,filter builtin 创建了一个迭代器,当 advanced 时,它为迭代顺序中的每个元素(不同或不同)执行一次函数。

  • x in list1 在平均情况和最坏情况下对O(len(list1)) 进行比较,如记录所示。


要加快速度,请使用set;你也根本不需要 lambda 函数(使用 __contains__ 魔术方法)

list3 = filter(set(list1).__contains__, list2)

这会在O(len(list1)) 时间内构建一次list1set,并以O(len(list2))O(len(list1) + len(list2)) 的平均复杂度对其运行过滤器


如果list2元素的顺序没关系那么你也可以这样做

set(list1).intersection(list2)

应该比上面的filter 有更低的常数;对于真正快速的代码,您应该对列表进行排序,以便 smaller 变成一个集合(因为交集和集合构建都记录了O(n) 的平均复杂度,但集合构建很可能会有由于调整 set 的大小而导致的较大常量,因此从较小的值构建集合以减少这些常量的权重是有意义的):

smaller, larger = sorted([list1, list2], key=len)
result = set(smaller).intersection(larger)

请注意,Python 2 和 3 彼此不同。 Python 3 中的filter 返回一个生成器,实际运行时间取决于生成的生成器消耗的元素数量,而在 Python 2 中将预先生成一个列表,如果您只需要第一个值,这可能会更昂贵.

【讨论】:

  • 你怎么知道filter函数的时间复杂度?在这里没找到:wiki.python.org/moin/TimeComplexity
  • @Controll:我们知道它是如何工作的——它遍历列表,在列表的每个元素上调用给定函数来决定是否将该元素保留在新列表中——这足以计算它的复杂性。
  • 当然不是。但这就是它的工作原理,该函数对参数中消耗的每个元素执行一次。
  • 有没有办法验证这是正确的复杂性分析,一些库可以做到这一点?
  • timeit.timeit 与不同的随机输入一起使用。
【解决方案2】:

复杂度可能是O(nm),其中nlist1 的大小,mlist2 的大小。然而,这种分析虽然看似合理,但取决于交叉的底层 python 实现(可能使用排序,因此复杂度可能是 O(logn+logm) 或 sth)

为了对此进行实验性测试并验证结果,请使用:

  1. 生成具有不同项目和大小(包括重复项)的各种测试列表
  2. 用测试列表和measure the time taken测试函数
  3. 绘制时间与列表大小的结果以验证(实验性)复杂性

【讨论】:

  • 据说这两个是lists,毫无疑问它是如何工作的。我已经发布了一个答案,你的只是增加了混乱
  • @NikosM.:我可以在这里提醒您行为准则吗(请参阅help center)。告诉某人迷路是可接受的行为。
  • 过滤器只在n 之外的任何时间运行,并且消耗了 n 个元素;即使list 可以理论上支持 Python 的某些替代实现中的快速成员资格测试(据我所知,它在任何情况下都没有),替代实现可能 filter 以对数时间运行,因此 log m 不会发生。
  • @AnttiHaapala,正如答案所述,它涉及测试交叉点功能。当然 filter 将为列表中的每个 elemtn 运行(已经提到过)。第一次谈交集功能。希望能读懂的人都清楚。就实现而言,我不知道,我想你也不知道 python 的内部结构及其在每个版本中使用的所有算法。即使在这种情况下,实验测试也应该体现这一点,并且肯定会消除任何混淆
  • 如果您继续像您一样回复,那么您将来会得到的只是人们在没有留下反馈的情况下投反对票,因为他们不想被卷入与您的讨论中有。这不会帮助您改进这些帖子或从您可能犯的任何错误中吸取教训。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-21
  • 2022-09-25
  • 2022-10-25
  • 1970-01-01
  • 2019-03-13
  • 2022-07-01
  • 2015-02-21
相关资源
最近更新 更多