我一直在尝试使用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 ?
我很想知道其他想到的解决方案。
感谢。
答案 0 :(得分:1)
您的解决方案并不是很糟糕 - 您还可以查看重新处理SequenceMatcher,以便在序列的元素本身可迭代时递归应用,并使用一些自定义逻辑。那将是一种痛苦。如果您只想要这个SequenceMatcher功能的子集,那么编写自定义diff工具也可能不是一个坏主意。
覆盖__hash__
以使"Foo"
和"Fo"
相等会导致字典(哈希表)等冲突。如果你真的只对前两个字符感兴趣并且使用SequenceMatcher设置,那么返回cls.super(self[2:])
可能就好了。
所有这一切,你最好的选择可能是一次性差异工具。如果您有兴趣,我可以勾画出类似的基础知识。你只需要知道在这种情况下约束是什么(子序列总是从第一个元素开始,那种事情)。