我一直在尝试使用 SequenceMatcher 创建嵌套或递归效果。
最终目标是比较两个序列,它们都可能包含不同类型的实例。
例如,序列可以是:
l1 = [1, "Foo", "Bar", 3]
l2 = [1, "Fo", "Bak", 2]
通常,SequenceMatcher 只会将 [1] 识别为 l1 和 l2 的公共(public)子序列。
我希望将 SequnceMatcher 应用于字符串实例两次,以便 "Foo"
和 "Fo"
将被视为相等, 以及 "Bar"
和 "Bak"
, 最长公共(public)子序列的长度为 3 [1, Foo/Fo, Bar/烘焙]
。也就是说,我希望 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 的文档说明如下:
This is a flexible class for comparing pairs of sequences of any type, so long as the sequence elements are hashable.
根据定义,可哈希元素需要满足以下要求:
Hashable objects which compare equal must have the same hash value.
此外,我是否还需要覆盖 cmp?
我很想听听想到的其他解决方案。
谢谢。
最佳答案
您的解决方案还不错 - 您还可以考虑重新设计 SequenceMatcher,以便在序列元素本身是可迭代对象时递归应用一些自定义逻辑。那将是一种痛苦。如果您只需要 SequenceMatcher 的这个功能子集,那么编写自定义 diff 工具也不是一个坏主意。
重写 __hash__
使 "Foo"
和 "Fo"
相等将导致字典(哈希表)等发生冲突。如果您实际上只对前 2 个字符感兴趣并且准备使用 SequenceMatcher,则返回 cls.super(self[2:])
可能是可行的方法。
综上所述,您最好的选择可能是一次性差异工具。如果你有兴趣,我可以勾勒出类似的基础知识。您只需要知道在这种情况下的约束是什么(子序列是否总是从第一个元素开始,诸如此类)。
关于python - Difflib 的 SequenceMatcher - 自定义相等,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18672130/