2013-09-07 3 views
6

Я пытаюсь создать вложенный или рекурсивный эффект с помощью SequenceMatcher.SequenceMatcher Difflib - Индивидуальное равенство

Конечной целью является сравнение двух последовательностей, оба могут содержать экземпляры разных типов.

Например, последовательности могут быть:

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 был более прощающим при сравнении членов строки.

То, что я пытался делать это написать оболочку для встроенного ул класса:

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 

Edit: возможно, более элегантный способ:

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

Ваше решение неплохое - вы также можете рассмотреть возможность повторного использования SequenceMatcher для рекурсивного применения, когда элементы последовательности сами являются итерабельными, с некоторой пользовательской логикой. Это было бы болью. Если вы хотите только это подмножество функций SequenceMatcher, написать собственный инструмент сравнения не может быть и плохой идеей.

Переопределение __hash__ сделать "Foo" и "Fo" равным вызовет столкновения в словарях (хеш-таблицах) и тому подобное. Если вас буквально интересуют только первые 2 символа и устанавливаются с использованием SequenceMatcher, возвращение cls.super(self[2:]) может быть путем.

Все, что сказал, лучший выбор - это, возможно, одноразовый инструмент. Я могу набросать основы чего-то подобного, если вам интересно. Вам просто нужно знать, каковы ограничения в обстоятельствах (всегда ли начинается подпоследовательность первого элемента, такого рода вещи).

+0

Можете ли вы подробнее рассказать об одноразовом инструменте diff? Разве это не переполнение, чтобы повторно реализовать алгоритм сопоставления? – geckon

+0

Ну, это зависит от ситуации и ограничений. Если вы ищете строгое равенство, кроме как в случае строк (или всех подэлементов?), И порядок всегда один и тот же, и вы знаете, где должно начинаться сопоставление ... Или 2 из этих 3, или что-нибудь еще. Обобщенный алгоритм не всегда лучший, потому что адаптация его к вашим потребностям может быть сложнее, чем просто сделать что-то новое, что делает то, что вы хотите. –

+0

Ну, у меня есть две последовательности (скажем, списки) объектов, и я хочу найти разницу между ними. Но для сравнения я не хочу использовать какой-либо метод класса объектов (даже не '__hash__',' __eq__' и т. Д.), Но я хочу предоставить функцию, которая будет вызываться с каждым объектом в качестве параметра, а возвращаемое значение будет использовано для сравнения. Эта «функция генерации ключей» будет написана мной и может использовать методы класса объектов, стандартные функции и т. Д. И вернется, скажем, строку. Но он может быть более общим (обратный тип). – geckon

Смежные вопросы