Difflib的SequenceMatcher - 定制的相等

时间:2013-09-07 10:03:01

标签: python difflib sequencematcher

我一直在尝试使用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

所以,显然它有效,但我对覆盖哈希功能感到不好。 什么时候使用哈希?哪里可以回来咬我?

SequenceMatcher的文档陈述如下:

  

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

根据定义,可以使用hashable元素来满足以下要求:

  

比较相等的Hashable对象必须具有相同的哈希值

此外,我是否还需要覆盖 cmp

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

感谢。

1 个答案:

答案 0 :(得分:1)

您的解决方案并不是很糟糕 - 您还可以查看重新处理SequenceMatcher,以便在序列的元素本身可迭代时递归应用,并使用一些自定义逻辑。那将是一种痛苦。如果您只想要这个SequenceMatcher功能的子集,那么编写自定义diff工具也可能不是一个坏主意。

覆盖__hash__以使"Foo""Fo"相等会导致字典(哈希表)等冲突。如果你真的只对前两个字符感兴趣并且使用SequenceMatcher设置,那么返回cls.super(self[2:])可能就好了。

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