7

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

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

例如,序列可以是:

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

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

我希望 SequnceMatcher 对 string instances 应用两次,以便"Foo"and 和 and"Fo"被认为是相等的,"Bar"并且"Bak"最长的公共子序列的长度为 3 [1, Foo/Fo, Bar/Bak]。也就是说,我希望 SequenceMatcher在比较 string members 时更加宽容

我尝试做的是为内置 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 的文档说明如下:

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

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

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

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

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

谢谢。

4

1 回答 1

1

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

覆盖__hash__make"Foo""Fo"equal 将导致字典(哈希表)等中的冲突。如果您实际上只对前 2 个字符感兴趣并开始使用 SequenceMatcher,那么返回cls.super(self[2:])可能是您的选择。

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

于 2015-05-18T21:27:08.363 回答