Unwind по существу правильно, что существует много разных способов реализации trie; и для больших масштабируемых триггеров вложенные словари могут стать громоздкими или, по крайней мере, неэффективными. Но поскольку вы только начинаете, я думаю, что это самый простой подход; вы можете создать простой trie
всего несколько строк. Во-первых, функция для построения trie:
>>> _end = '_end_'
>>>
>>> def make_trie(*words):
... root = dict()
... for word in words:
... current_dict = root
... for letter in word:
... current_dict = current_dict.setdefault(letter, {})
... current_dict[_end] = _end
... return root
...
>>> make_trie('foo', 'bar', 'baz', 'barz')
{'b': {'a': {'r': {'_end_': '_end_', 'z': {'_end_': '_end_'}},
'z': {'_end_': '_end_'}}},
'f': {'o': {'o': {'_end_': '_end_'}}}}
Если вы не знакомы с setdefault
, она просто ищет ключ в словаре (здесь letter
или _end
), , Если ключ присутствует, он возвращает соответствующее значение; если нет, он присваивает значение по умолчанию этому ключу и возвращает значение ({}
или _end
). (Это похоже на версию get
, которая также обновляет словарь.)
Далее, функция для проверки того, находится ли слово в trie. Это может быть более кратким, но я оставляю его подробным, чтобы логика была ясной:
>>> def in_trie(trie, word):
... current_dict = trie
... for letter in word:
... if letter in current_dict:
... current_dict = current_dict[letter]
... else:
... return False
... else:
... if _end in current_dict:
... return True
... else:
... return False
...
>>> in_trie(make_trie('foo', 'bar', 'baz', 'barz'), 'baz')
True
>>> in_trie(make_trie('foo', 'bar', 'baz', 'barz'), 'barz')
True
>>> in_trie(make_trie('foo', 'bar', 'baz', 'barz'), 'barzz')
False
>>> in_trie(make_trie('foo', 'bar', 'baz', 'barz'), 'bart')
False
>>> in_trie(make_trie('foo', 'bar', 'baz', 'barz'), 'ba')
False
Я оставлю вставку и удаление в качестве упражнения.
Конечно, предложение Уотвинда было бы не намного сложнее. Может быть небольшое недостаток скорости в том, что поиск правильного подузла потребует линейного поиска. Но поиск будет ограничен числом возможных символов - 27, если мы включим _end
. Кроме того, нет ничего, что можно было бы получить, создав массивный список узлов и получив доступ к ним по индексу, как он предлагает; вы также можете просто вложить списки.
Наконец, я добавлю, что создание DAWG было бы немного сложнее, потому что вы должны обнаружить ситуации, в которых ваше текущее слово разделяет суффикс с другим словом в структуре. Фактически, это может стать довольно сложным, в зависимости от того, как вы хотите структурировать DAWG! Возможно, вам придется изучить некоторые вещи о Levenshtein distance , чтобы понять это правильно.