18.6. 优化字符串操作

Soundex 算法的最后一步是用零填充短结果,并截断长结果。实现此目的的最佳方法是什么?

这是我们目前所做的,取自 soundex/stage2/soundex2c.py

    digits3 = re.sub('9', '', digits2)
    while len(digits3) < 4:
        digits3 += "0"
    return digits3[:4]

以下是 soundex2c.py 的结果

C:\samples\soundex\stage2>python soundex2c.py
Woo             W000 12.6070768771
Pilgrim         P426 14.4033353401
Flingjingwaller F452 19.7774882003

首先要考虑的是用循环替换正则表达式。这段代码来自 soundex/stage4/soundex4a.py

    digits3 = ''
    for d in digits2:
        if d != '9':
            digits3 += d

soundex4a.py 是否更快?是的,它更快

C:\samples\soundex\stage4>python soundex4a.py
Woo             W000 6.62865531792
Pilgrim         P426 9.02247576158
Flingjingwaller F452 13.6328416042

但是等等。使用循环从字符串中删除字符?我们可以使用一个简单的字符串方法来做到这一点。以下是 soundex/stage4/soundex4b.py

    digits3 = digits2.replace('9', '')

soundex4b.py 是否更快?这是一个有趣的问题。这取决于输入

C:\samples\soundex\stage4>python soundex4b.py
Woo             W000 6.75477414029
Pilgrim         P426 7.56652144337
Flingjingwaller F452 10.8727729362

对于大多数名称,soundex4b.py 中的字符串方法比循环更快,但在简单情况下(非常短的名称),它实际上比 soundex4a.py 稍慢。性能优化并不总是统一的;使一种情况更快的调整有时会使其他情况更慢。在这种情况下,大多数情况都将受益于此更改,因此我们将其保留,但该原则是需要记住的重要原则。

最后但并非最不重要的一点是,让我们检查一下算法的最后两个步骤:用零填充短结果,以及将长结果截断为四个字符。您在 soundex4b.py 中看到的代码就是这样做的,但效率极低。看看 soundex/stage4/soundex4c.py 就明白了

    digits3 += '000'
    return digits3[:4]

为什么我们需要一个 while 循环来填充结果?我们事先知道要将结果截断为四个字符,并且我们知道我们至少已经有一个字符(初始字母,它从原始 source 变量传递而未更改)。这意味着我们可以简单地在输出中添加三个零,然后将其截断。不要拘泥于问题的措辞;稍微换个角度看待问题可能会找到更简单的解决方案。

通过删除 while 循环,我们在 soundex4c.py 中获得了多少速度?非常显著

C:\samples\soundex\stage4>python soundex4c.py
Woo             W000 4.89129791636
Pilgrim         P426 7.30642134685
Flingjingwaller F452 10.689832367

最后,您还可以对这三行代码做一件事,使它们更快:您可以将它们合并为一行。看看 soundex/stage4/soundex4d.py

    return (digits2.replace('9', '') + '000')[:4]

将所有这些代码放在 soundex4d.py 的一行中,速度 barely 比 soundex4c.py

C:\samples\soundex\stage4>python soundex4d.py
Woo             W000 4.93624105857
Pilgrim         P426 7.19747593619
Flingjingwaller F452 10.5490700634

它的可读性也大大降低,而且性能提升不大。这样做值得吗?我希望你有好的注释。性能并不是一切。您的优化工作必须始终与程序可读性和可维护性方面的威胁相平衡。