比较两个字符串是否相等的超级快速方法

2024-04-11

显然,在Python中检查两个字符串是否相等你可以这样做:

"hello word" == "hello world"

但是,如果您要比较很长的字符串(超过 100 万个字符)怎么办? python 中是否有内置方法或任何库可以更快地完成此操作;也许利用卡普-拉宾算法或类似的算法?

或者,在幕后, stringA == stringB 实际上是最快的方法吗?


(EDITED:提高综合素质)。

考虑如何str == str is 用Python实现 https://stackoverflow.com/questions/43466106/what-happens-when-you-compare-two-strings-in-python,这首先得到一个id()检查,长度检查,然后逐个元素进行。 这非常快并且可以理解,因为很多 Python 代码都依赖于此。 在一般情况下,不需要进一步优化,因为任意字符串很早就会有所不同。

然而,有两个用例有一些优化的空间:

  • 你有一些部分信息how两个输入将会不同。
  • 您在一组特定元素之间执行多重比较(请参阅@wim 评论)。

第一种情况的一个例子是:如果你知道当两个相同大小的输入不同时,它们是likely至少不同m连续的元素,然后每隔一个进行比较k元素与k < m将是一个合理的赌注,例如:

def is_k_equal(a, b, k=4096):
    if k in {0, 1}:
        return a == b
    else:
        return a[::k] == b[::k]


def is_equal_partial(a, b, partial_match=is_k_equal):
    return len(a) == len(b) and partial_match(a, b) and a == b

第二种情况的一个例子是:如果你想知道哪个p输入出q两两相等,计算哈希可能会有好处(例如使用hash(),但其他选项可能同样有效)的输入,并且仅在哈希匹配时才执行完整比较。 不言而喻,如果您的哈希具有较高的冲突等级,它可能只会引入额外的开销(请参阅维基百科有关哈希的信息 https://en.wikipedia.org/wiki/List_of_hash_functions)。 输入的哈希值可以手动管理,或者您可以保护您的full与 a 中的哈希比较进行比较is_equal()函数,例如:

def is_equal_hashing(a, b, hashing=hash):
    return len(a) == len(b) and hashing(a) == hashing(b) and a == b

假设你的散列函数是memoized https://en.wikipedia.org/wiki/Memoization. For hash()您不需要做任何其他事情,因为这些输入已经被记住了。 如果您要使用更高级的哈希(例如 crc32、md5 等),您可能需要自己添加记忆,例如@functools.lru_cache。 该用例从这种方法中获益的条件(忽略比较哈希值所需的时间,该时间通常比要考虑的其他操作快得多)是:

t_h * n_h < t_c * n_c

with t_h初始哈希计算时间,n_h的数量unique要计算的哈希值,t_c比较时间,以及n_c在输入末尾附近失败的完整比较的数量。

当对您的输入将如何执行有疑问时,通常最好measure / profile你的代码。

在对记忆函数进行计时时必须小心(例如hash()),因为,如果您对非记忆化路径的性能感兴趣,则不能像通常那样依赖同一输入的多次重复调用的计时,例如使用 IPython 的%timeit使用默认参数。相反,您可以使用%timeit -n1 -r1对于未缓存的计时。结果仅对数量级估计有用。

为了让您了解您的方法的可能成分有多快,以下是一些微基准:

import hashlib
import functools


def md5(data):
    return hashlib.md5(data).digest()


@funtools.lru_cache(maxsize=16384)
def sha1(data):
    return hashlib.sha1(data).digest()


def sha256(data):
    return hashlib.sha1(data).digest()


def sha512(data):
    return hashlib.sha1(data).digest()
import numpy as np
import numba as nb


@nb.jit(fastmath=True)
def hash_sum_nb(data, init=0):
    dtype = np.uint64
    nbytes = 8
    n = len(data)
    offset = n % nbytes
    result = init
    if offset:
        body = np.frombuffer(data[:-offset], dtype=dtype)
        tail = np.frombuffer(data[-offset:], dtype=np.uint8)
        for x in tail:
            result += x
    else:
        body = np.frombuffer(data, dtype=dtype)
    for x in body:
        result += x
    return result + n
import zlib
import string
import random


n = 1_000_000
s = b''.join(string.printable[random.randrange(len(string.printable))].encode() for _ in range(n))
funcs = hash, hash, zlib.crc32, zlib.adler32, md5, sha1, sha1, sha256, sha512, hash_sum_nb
for func in funcs:
    result = %timeit -n1 -r1 -q -o func(s)
    print(f'{func.__name__:>12s}  {result.best * 1e6:.3f} µs')
#         hash  586.401 µs
#         hash  0.853 µs
#        crc32  976.128 µs
#      adler32  468.452 µs
#          md5  1790.659 µs
#         sha1  1362.948 µs
#         sha1  1.423 µs
#       sha256  1347.432 µs
#       sha512  1321.981 µs
#  hash_sum_nb  64.768 µs


cases = {
    'worst case': (s[:-1] + b'x', s[:-1] + b'y'),
    'best case*': (s[:-1], s[:-2]),
    'best case': (b'x' + s[:-1], b'y' + s[:-1]),
}
for name, (a, b) in cases.items(): 
    result = %timeit -n1 -r1 -q -o a == b
    print(f'str == str ({name:10s})  {result.best * 1e6:.3f} µs')
# str == str (worst case)  142.466 µs
# str == str (best case*)  0.856 µs
# str == str (best case )  1.012 µs


a, b = (s[:-1] + b'x', s[:-1] + b'y')
result = %timeit -n1 -r1 -q -o is_k_equal(a, b)
print(f'{is_k_equal.__name__:>12s}  {result.best * 1e6:.3f} µs')
# is_k_equal  10.037 µs

请注意,两者hash() and sha1()在同一输入上调用两次以显示记忆的效果。

有了这些数据(或您可以在输入/系统上生成的类似数字),就有可能制作出性能更高的字符串相等性比较。 请注意,我在整个答案中使用了bytes反而。 的时间为str对于大多数散列来说通常会更糟,因为处理编码需要额外的开销,但值得注意的例外hash().


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

比较两个字符串是否相等的超级快速方法 的相关文章

  • 使用 Python Multiprocessing Pool.map() 的问题在 Python 3.7.2 中变得棘手,但在 3.6.2 中很快完成

    我刚刚将Python从3 6 2 gt 3 7 2并且遇到了问题multiprocessing图书馆 我在 Django 应用程序中使用它 该应用程序在工作函数中使用 Django 特定的函数 见下文 在我的代码中 我有以下内容 impor
  • Python 转换矩阵

    我有一个如下所示的列表 2 1 3 1 2 3 1 2 2 2 我想要的是一个转换矩阵 它向我显示如下序列 1 后跟 1 的频率是多少 1 后面跟着 2 的频率是多少 1 后跟 3 的频率是多少 2 后跟 1 的频率是多少 2 后跟 2 的
  • 如何使用一个模型中间层的输出作为另一个模型的输入?

    我训练一个模型A并尝试使用中间层的输出name layer x 作为模型的附加输入B 我尝试像 Keras 文档一样使用中间层的输出https keras io getting started faq how can i obtain th
  • 为什么在连接两个字符串时 Python 比 C 更快?

    目前我想比较 Python 和 C 用来处理字符串的速度 我认为 C 应该比 Python 提供更好的性能 然而 我得到了完全相反的结果 这是 C 程序 include
  • 查找正在导入哪些 python 模块

    从应用程序中使用的特定包中查找所有 python 模块的简单方法是什么 sys modules是将模块名称映射到模块的字典 您可以检查其键以查看导入的模块 See http docs python org library sys html
  • 带有 mkdocs 的本地 mathjax

    我想在无法访问互联网的计算机上使用 MathJax 和 Mkdocs 因此我不能只调用 Mathjax CDN Config mkdocs yml site name My Docs extra javascript javascripts
  • App Engine NDB:如何访问属性的 verbose_name

    假设我有这个代码 class A ndb Model prop ndb StringProperty verbose name Something m A m prop a string value 当然 现在如果我打印 m prop 它会
  • Django 多对多关系(类别)

    我的目标是向我的 Post 模型添加类别 我希望以后能够按不同类别 有时是多个类别 查询所有帖子 模型 py class Category models Model categories 1 red 2 blue 3 black title
  • Python - Unicode 到 ASCII 的转换

    我无法在不丢失数据的情况下将以下 Unicode 转换为 ASCII u ABRA xc3O JOS xc9 I tried encode and decode他们不会这么做 有人有建议吗 Unicode 字符u xce0 and u xc
  • 如何用正则表达式替换多个匹配/组?

    通常我们会编写以下内容来替换一场比赛 namesRegex re compile r is life re I replaced namesRegex sub r butter There is no life in the void pr
  • 无法使用 python rasterio、gdal 打开 jp2 (来自哨兵)

    我试图在 python 中将 jp2 栅格产品作为栅格打开 但当我们使用 raterio 和 gdal 包时没有成功 我收到此错误 RasterioIOError b4 jp2 not recognized as a supported f
  • 为什么 Collections.counter 这么慢?

    我正在尝试解决罗莎琳德的基本问题 即计算给定序列中的核苷酸 并在列表中返回结果 对于那些不熟悉生物信息学的人来说 它只是计算字符串中 4 个不同字符 A C G T 出现的次数 我期望collections Counter是最快的方法 首先
  • 是否可以在Python中将日+月(不是年)与当前日+月进行比较?

    我正在获取 5 月 10 日 格式的数据 我试图弄清楚它是今年还是明年 该日期仅一年 因此 5 月 10 日表示 2015 年 5 月 10 日 而 5 月 20 日表示 2014 年 5 月 20 日 为此 我想将字符串转换为日期格式并进
  • 从 wxPython 事件处理程序中调用函数

    我正在努力寻找一种在 wxPython 事件处理函数中使用函数的方法 假设我有一个按钮 单击该按钮时 它会使用事件处理程序运行一个名为 OnRun 的函数 但是 用户忘记单击 OnRun 按钮之前的 RadionButton 我想弹出一个
  • Python 2.7 缩进错误[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 这个问题是由拼写错误或无法再重现的问题引起的 虽然类似的问题可能是on topic help on topic在这里 这个问题的解决方式不
  • Python:如何在不先创建整个列表的情况下计算列表的总和?

    通常我们必须 1 声明一个列表 2 使用以下方法计算该列表的总和sum 但现在我希望指定一个以 1 开头 间隔为 4 100 个元素的列表 如下所示 1 5 9 13 17 21 25 29 33 37 我不想涉及数学公式 所以 1 如何在
  • Python 相当于 Scala 案例类

    Python 中是否有与 Scala 的 Case Class 等效的东西 就像自动生成分配给字段而无需编写样板的构造函数一样 当前执行此操作的现代方法 从 Python 3 7 开始 是使用数据类 https www python org
  • 使用 pandas 单元格中列表的长度选择行[重复]

    这个问题在这里已经有答案了 我有一张表 df a b c 1 x y x 2 x z c d 3 x t e f g 只是想知道如何使用 c 列的长度选择行 such as df loc len df c gt 1 我知道这是不对的 正确的
  • 如何使用 Python/Django 在 Facebook 中获取(和使用)扩展权限

    我正在尝试编写一个简单的应用程序 让用户授予我的代码写入其页面的 Facebook 流的权限 据我了解 它应该很简单 让用户单击一个按钮 启动一个弹出窗口 其中包含我的 Facebook 应用程序中的页面 在该页面中 他们单击授予的内容流发
  • MoviePY 无法在 Windows 上检测 ImageMagick 二进制文件

    我刚买了一台新笔记本电脑 想要设置MoviePY在那新的Windows 64x Python3 7 0 机器 我对所有内容都进行了三次检查 但是当涉及到我的代码的文本部分时 它向我抛出了这个错误 OSError MoviePy Error

随机推荐