【问题标题】:Which function is better for removing characters from strings - Time complexity哪个函数更适合从字符串中删除字符 - 时间复杂度
【发布时间】:2020-04-18 23:33:55
【问题描述】:

我需要构建一个从 Python 中的字符串中删除所有数字的函数,但是我的问题不在于如何做到这一点(因为我从这里以前的帖子中知道)

我对这两个函数的复杂性有疑问,一个是使用过滤器和 lambda 函数来删除数字,另一个是使用正则表达式,来自具有非常长字符串(~67,912,000 个字符 +)的基本测试
我得出的结论是正则表达式更快,但是我不知道实际的复杂性,因此我的“计算”不正确/对计算机规格有偏见(也许我的计算机速度很快,而其他的计算机速度很慢,反之亦然...... )
从互联网上阅读the filter functioncomplexity of regex 的复杂性 我知道他们都是 O(n)..

那么,哪一个在内存/时间复杂度上“过大”,哪一个不是。您应该使用哪一个(作为一种更好的做法)?:

import time
import re

def dwf(word):
    start = time.time()
    word = ''.join((filter(lambda x: x.isalpha(), word)))
    end = time.time()
    return end - start



def dwr(word):
    start = time.time()
    word = re.sub(r"\d+", '', word)
    end = time.time()
    return end-start

例如,对我来说:
如果这个词是 6700 万~chars,时间差接近 7 秒! (当过滤器更长且正则表达式更快时)

【问题讨论】:

  • 如果你关心速度,你应该编译你的正则表达式(一次)。
  • @TomKarzes 'compile (once)' 是什么意思,或者我没有完全得到你的答案,你基本上是说使用过滤器是一种矫枉过正,我应该使用正则表达式跨度>
  • @TomKarzes - re 保留最近正则表达式的缓存。只要不大量使用,就不需要预编译。
  • 即使它们都具有相同的复杂性,它们仍然可能线性相差 100 倍。正则表达式是用 C 编写的,只在几个缓冲区上工作。在您的过滤器示例中,您需要为每个字符创建一个对象并调用该 lambda 函数。这里没有竞争!
  • Python 是一门很棒的语言,但它的对象模型相当庞大。当您执行filter(..., word) 时,word 中的每个字符都需要转换为具有单个字符(约 50 个字节)的str,需要为lambda 等创建一个框架对象...... Python 的正则表达式引擎在 C 中实现,因此它可以处理内存中的原始字符。任何语言都可以在本地实现正则表达式,但是由于性能优势,基于 C 的语言(如 python(无论如何是 cpython))经常退回到 C 进行此操作。

标签: python regex filter time-complexity big-o


【解决方案1】:

既然你已经知道它需要 O(n),我会进一步说你需要弄清楚你的输入情况(这里是 word),即最好和最坏的情况,看看你是否得到相同的时间复杂度O(n) 对于您正在尝试的方法。

对于空间复杂度,我发现这两种方法平均给你 O(1)。

【讨论】:

    【解决方案2】:

    不同的方法是 O(n),但由于不同的比例因子,一些方法要快得多。

    例如计时测试显示maketrans 比OP 方法快得多。

    方法

    def dwf(word):
        " Filter method "
        return ''.join((filter(lambda x: x.isalpha(), word)))
    
    
    def dwr(word):
        " Regex method "
        return  re.sub(r"\d+", '', word)
    
    def trans(word):
        " Maketrans method "
        translation = str.maketrans("", "", string.digits)
        return word.translate(translation)
    

    测试

    使用 timeit 进行时间测量,因为它最可靠。

    设置

    随机字符串大小写+数字

    import string
    import random
    
    N = 1000000  # Million characters
    word = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(N))
    

    结果

    import timeit
    

    过滤器

    %timeit dwf(word)
     N = 1000 -> timeit: 280 us
     N = 1 M -> timeit:  241 ms
    

    正则表达式

    %timeit dwr(word)
    N = 1000 -> timeit: 84.6 us
    N = 1 M  -> timeit: 87.5 ms
    

    制作翻译

    %timeit trans(word)
    N = 1000 -> timeit: 11.4 us
    N = 1 M -> timeit:   3.78 ms
    

    结论

    通过将点数从 1K 增加到 1M 过滤器和正则表达式的时间增加了 ~1000(线性)

    Maketrans 仅增加了约 300,这意味着它在处理更大的字符串时效率更高。

    N = 1000

      Maketrans is 24X filter
    
      Maketrans is 7X Regex
    

    N = 1 M

      Maketrans is 63X filter
    
      Maketrans is 23X regex
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多