【问题标题】:'in' operator functionality in pythonpython中的'in'运算符功能
【发布时间】:2021-10-29 22:24:32
【问题描述】:

我需要删除string1 中存在的string2 中的字符。这里string1string2 只有小写字符a-z,条件是string1 的长度每次都会更大。

我使用的是in 运算符:

def removeChars (string1, string2):
    for char in string2:
        if char in string1:
            string1 = string1.replace(char, '')
    return string1

但我在 Stack Overflow 上读到了一个 answer,上面写着:

对于 list、tuple、set、frozenset、dict 或 collections.deque 等容器类型,表达式 x in y 等价于 any(x is e or x == e for e in y)

这意味着in 运算符在幕后使用for 循环。

所以我的问题是,在我的代码中的for 循环中,我是否应该考虑使用嵌套的for 循环,因为in 运算符在后台使用for 循环?如果是,这个程序的时间复杂度是多少?

【问题讨论】:

  • 你可能会觉得this很有趣。
  • "这意味着 'in' 运算符在幕后使用 for 循环。" 不,它没有。这个警告只是关于语义。例如,dictset 不涉及循环,而是基于哈希的查找。它的重点是in 将首先检查身份作为优化然后相等。
  • 您是在询问一般的in 还是专门询问字符串?
  • 这种特殊情况,是的,字符串之间的in 将涉及线性时间算法

标签: python time-complexity


【解决方案1】:

in 相当于一个循环时,它必须“遍历”迭代器并依次比较每个项目。

这意味着每个循环都是O(n),所以对于 2 个级别,这是O(n²)

https://wiki.python.org/moin/TimeComplexity

请注意,这里实际上有 3 个循环 - 因为您的 replace 也会遍历字符串。

由于如果没有找到char,replace 不会引发任何错误,因此在不先测试char in string1 的情况下执行此操作会更简单。

【讨论】:

  • in 不一定等同于循环。这取决于所涉及的类型
  • 请注意,由于这是关于删除许多字符,因此使用 translation table 可能是 O(n+m) 时的最佳复杂度。
  • @juanpa.arrivillaga 是的 - 因此我说“When in 相当于一个循环”。我打算写一个更长的解释,但上面的 Ofer 已经涵盖了。
【解决方案2】:

in 不一定在幕后使用循环。例如:

r = range(100000000000)
print(333 in r)  # prints True immediately without looping

如果您要循环 r,这将需要很长时间,所以显然不会发生这种情况。

in 基本上调用(在幕后)对象的__contains__ 方法。对于某些迭代器,它实际上会“循环”所有内容,但情况并非总是如此。

这个例子和调用基本一样:

r.__contains__(333)

正如 cmets 中所指出的 - str 对象具有比普通循环更智能的算法,如您所见 here

另见示例答案here

并查看文档here

因为现实世界的场景可能意味着 string1 可以任意长,但要删除的字符将是一个有限且小的集合,因此将所有字符相加可能会更有效率不在string2。像这样的:

def removeChars (string1, string2):
    result = ''
    for char in string1:
        if char not in string2:
            result += char
    return result

这将涉及仅循环一次string1,但使用instring2 进行多次检查。这可以进一步简化(以避免+= 循环结果):

def removeChars (string1, string2):
    return ''.join(char for char in string1 if char not in string2)

【讨论】:

  • 也不适用于str (stackoverflow.com/questions/18139660/…)。复杂性将与O(n^2) 有关。 O(n^2m) 在最坏的情况下。
  • 这个问题非常明确地谈论字符串,所以不提这个案例似乎没有抓住重点。
  • @MisterMiyagi 你是对的,我已经添加了一些关于字符串的小说明
  • nnooooo。这可能会导致灾难性的二次行为,循环中的result += char 将是二次时间,尽管 CPython 运行时中有一个优化可以避免这种情况,不建议依赖它,您应该始终使用list,最后是''.join
  • 正如在另一个答案的评论中提到的,字符串已经有一种方法可以一次删除任意多个字符:str.translate
【解决方案3】:

你确实有一个嵌套的 for 循环,但是,它不需要完全执行(平均而言),只需要直到它达到匹配。

所以最好的情况是 O(n) -- 如果每个列表的所有元素都匹配,那么对于列表 1 的每个元素,它需要内部循环的一步来确定它是否匹配。

最坏情况是 O(n^2) -- 如果只有列表 2 的最后一个元素匹配,则外循环的每次迭代都需要测试内循环 n 次。

至少,我是这么理解的,但是,不是专家。

【讨论】:

  • 平均情况是“打中”,即O(n/2) == O(n)。
  • 那么这会使平均双循环考虑 O(n*n/2) -> O(n^2) 吗? (编辑:在示例字符串的情况下。谢谢。)
  • 技术上 O(n m)(“n 乘以 m”),其中 n 和 m 是两个字符串的大小。
猜你喜欢
  • 1970-01-01
  • 2012-07-11
  • 1970-01-01
  • 2011-01-14
  • 1970-01-01
  • 1970-01-01
  • 2018-06-14
  • 2012-12-02
相关资源
最近更新 更多