【问题标题】:Making a python loop faster使python循环更快
【发布时间】:2018-05-08 13:40:34
【问题描述】:

这个小程序可以更快吗?使用 elif 会使理解失控,但也许我没有以正确的方式尝试。

def cleanup(s):
    strng = ''
    good = ['\t', '\r', '\n']
    for char in s:        
        if unicodedata.category(char)[0]!="C":
            strng += char
        elif char in good:
            strng += char
        elif char not in good:
            strng += ' '
    return strng

【问题讨论】:

  • 至少你可以通过将elif char not in good:更改为else:来加快速度。如果您希望某人找到更好的方法,请添加示例 stringunicodedata.category 并详细说明您在做什么。
  • 一般来说,some_string += some_other_string 在循环中会很慢。它具有二次复杂度(尽管解释器会尝试对其进行优化),但是,您应该将其折射为使用 list.append,然后在最后使用 ''.join

标签: python python-2.7 performance for-loop


【解决方案1】:

如果我正确理解您的任务,您希望将所有 unicode 控制字符替换为空格 except \t\n\r

这里是如何使用正则表达式而不是循环更有效地做到这一点。

import re

# make a string of all unicode control characters 
# EXCEPT \t - chr(9), \n - chr(10) and \r - chr(13)
control_chars = ''.join(map(unichr, range(0,9) + \
                            range(11,13) + \
                            range(14,32) + \
                            range(127,160)))

# build your regular expression
cc_regex = re.compile('[%s]' % re.escape(control_chars))

def cleanup(s):
    # substitute all control characters in the regex 
    # with spaces and return the new string
    return cc_regex.sub(' ', s)

您可以通过操作构成control_chars 变量的范围来控制要包含或排除的字符。参考List of Unicode characters

编辑计时结果。

出于好奇,我进行了一些计时测试,看看当前的三种方法中哪一种最快。

我创建了三个名为 cleanup_op(s) 的方法,它们是 OP 代码的副本; cleanup_loop(s) 这是 Cristian Ciupitu 的回答; cleanup_regex(s) 这是我的代码。

这是我跑的:

from timeit import default_timer as timer

sample = u"this is a string with some characters and \n new lines and \t tabs and \v and other stuff"*1000

start = timer();cleanup_op(sample);end = timer();print end-start
start = timer();cleanup_loop(sample);end = timer();print end-start
start = timer();cleanup_regex(sample);end = timer();print end-start

结果:

cleanup_op 在大约 1.1 秒内完成

cleanup_loop 在大约 0.02 秒

内完成

cleanup_regex 大约在 0.004 秒

内完成

因此,任何一个答案都是对原始代码的重大改进。我认为@CristianCiupitu 给出了一个更优雅和pythonic 的答案,而正则表达式仍然更快。

【讨论】:

  • 即使re.compile 有一个编译模式的小缓存,最好将规则表达式的编译移到cleanup 函数之外,这样就不会在每次调用时都执行此步骤.
  • 另外如果你想和OP做同样的事情,cc_regex.sub('', s)应该替换成cc_regex.sub(' ', s)(那些特殊字符被转换为空格,而不是被删除)。
  • @CristianCiupitu 当然,听起来不错。我修正了答案以反映您的建议。
  • 您的代码只处理来自 C0C1 类别的控制字符。您缺少 Cf(格式控制字符)、Cs(代理代码点)、Co(私人使用字符)和 Cn(保留的未分配代码点或非字符)。
  • 我也在 Intel i7-3770 CPU 上运行了一些 %timeit 基准测试,用于 3800 个字符的字符串(必须更换 200 个)。我更改了代码以使用与您的相同的有限控制字符集。在 python2-2.7.14-10.fc27.x86_64 上,正则表达式代码需要 69.4 µs,翻译代码需要 414 µs。在 python3-3.6.5-1.fc27.x86_64 上,结果为 56 µs ± 186 ns 和 4.32 µs ± 4.62 ns。
【解决方案2】:

如果我理解正确,您希望将所有 Unicode 控制字符转换为空格,tab回车换行除外。您可以为此使用str.translate

good = map(ord, '\t\r\n')
TBL_CONTROL_TO_SPACE = {
    i: u' '
    for i in xrange(sys.maxunicode)
    if unicodedata.category(unichr(i))[0] == "C" and i not in good
}

def cleanup(s):
    return s.translate(TBL_CONTROL_TO_SPACE)

【讨论】:

    猜你喜欢
    • 2022-10-15
    • 1970-01-01
    • 2016-06-01
    • 1970-01-01
    • 2016-05-30
    • 1970-01-01
    • 1970-01-01
    • 2016-09-14
    • 2021-02-13
    相关资源
    最近更新 更多