【问题标题】:Difflib's SequenceMatcher - Customized equalityDifflib 的 SequenceMatcher - 自定义相等
【发布时间】:2013-09-07 10:03:01
【问题描述】:

我一直在尝试使用 SequenceMatcher 创建嵌套或递归效果。

最终目标是比较两个序列,两者都可能包含不同类型的实例。

例如,序列可以是:

l1 = [1, "Foo", "Bar", 3]
l2 = [1, "Fo", "Bak", 2]

通常,SequenceMatcher 只会将 [1] 识别为 l1 和 l2 的公共子序列。

我希望 SequnceMatcher 对字符串实例应用两次,这样"Foo""Fo" 以及"Bar""Bak" 将被视为相等,并且最长公共子序列的长度为 3 [1, Foo/Fo, Bar/Bak]。也就是说,我希望 SequenceMatcher 在比较字符串成员时更宽容

我尝试做的是为内置的 str 类编写一个包装器:

from difflib import SequenceMatcher
class myString:
    def __init__(self, string):
        self.string = string
    def __hash__(self):
        return hash(self.string)
    def __eq__(self, other):
        return SequenceMatcher(a=self.string, b=self.string).ratio() > 0.5

编辑:也许更优雅的方式是:

class myString(str):
    def __eq__(self, other):
        return SequenceMatcher(a=self, b=other).ratio() > 0.5

通过这样做,以下是可能的:

>>> Foo = myString("Foo")
>>> Fo = myString("Fo")
>>> Bar = myString("Bar")
>>> Bak = myString("Bak")
>>> l1 = [1, Foo, Bar, 3]
>>> l2 = [1, Fo, Bak, 2]
>>> SequenceMatcher(a=l1, b=l2).ratio()
0.75

所以,显然它正在工作,但我对重写 hash 函数有一种不好的感觉。 什么时候使用哈希?它还能从哪里回来咬我?

SequenceMatcher 的文档说明如下:

这是一个灵活的类,用于比较任何类型的序列对, 只要序列元素是可散列的

根据定义,可散列元素需要满足以下要求:

比较相等的可散列对象必须具有相同的散列值

此外,我还需要覆盖 cmp 吗?

我很想听听我想到的其他解决方案。

谢谢。

【问题讨论】:

    标签: python difflib sequencematcher


    【解决方案1】:

    您的解决方案还不错 - 您还可以考虑重新设计 SequenceMatcher 以在序列元素本身是可迭代的情况下递归应用,并使用一些自定义逻辑。那将是一种痛苦。如果您只想要 SequenceMatcher 功能的这个子集,那么编写自定义差异工具也可能不是一个坏主意。

    覆盖__hash__ 以使"Foo""Fo" 相等会导致字典(哈希表)等发生冲突。如果您实际上只对前 2 个字符感兴趣并设置使用 SequenceMatcher,则返回 cls.super(self[2:]) 可能是要走的路。

    综上所述,您最好的选择可能是一次性差异工具。如果你有兴趣,我可以勾勒出类似的基础知识。您只需要知道在这种情况下的约束是什么(子序列是否总是从第一个元素开始,诸如此类)。

    【讨论】:

    • 您能详细说明一次性差异工具吗?重新实现匹配算法不是大材小用吗?
    • 嗯,这取决于情况和限制。如果您正在寻找除字符串(或所有子可迭代对象?)之外的严格相等性,并且顺序始终相同,并且您知道匹配应该从哪里开始......或者这 3 个中的 2 个,或者任何其他别的。通用算法并不总是最好的,因为根据您的需求对其进行定制可能比仅仅制作符合您需求的新东西更难。
    • 好吧,我有两个对象序列(比如说列表),我想找出它们之间的区别。但为了比较,我不想使用对象类的任何方法(甚至__hash____eq__ 等),但我想提供一个函数,将每个对象作为参数和返回值将用于比较。这个“密钥生成函数”将由我编写,可以使用对象类的方法、标准函数等,并且会返回一个字符串。但它也可以更通用(返回类型)。
    • 也许你可以给我一些示例输入和输出?不确定您的用例与 YaronK 最初声明的目标的匹配程度。
    • 我的用例是 YaronK 问题的通用版本。如果我尝试映射它,那么对象是字符串,“键生成函数”为每个要比较的给定对象(字符串)返回前两个字符。
    猜你喜欢
    • 2014-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-26
    相关资源
    最近更新 更多