Перемещение по словарю с использованием переменного количества ключей [duplicate]

Выбранная переменнаяHero имеет значение null в шаблоне, поэтому вы не можете привязать выбранноеHero.name как есть. Вам нужно использовать оператор elvis для этого случая:

<input [ngModel]="selectedHero?.name" (ngModelChange)="selectedHero.name = $event" />

Разделение [(ngModel)] в [ngModel] и (ngModelChange) также необходимо, потому что вы не можете назначить выражение который использует оператор elvis.

Я также думаю, что вы хотите использовать:

<h2>{{selectedHero?.name}} details!</h2>

вместо:

<h2>{{hero.name}} details!</h2>
93
задан Phil 13 June 2012 в 13:56
поделиться

8 ответов

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 , чтобы понять это правильно.

120
ответ дан Community 24 August 2018 в 10:28
поделиться

Взгляните на это:

https://github.com/kmike/marisa-trie

Статическая память Trie-структуры для Python (2.x и 3.x).

Строковые данные в MARISA-trie могут занимать до 50x100x меньше памяти, чем в стандартном Python dict; необработанная скорость поиска сопоставима; trie также предоставляет быстрые продвинутые методы, такие как префиксный поиск.

Основано на библиотеке C ++ для marisa-trie.

Вот сообщение в блоге от компании, использующей marisa trie успешно: http://blog.repustate.com/sharing-large-data-structure-across-processes-python/

В Repustate большинство наших моделей данных мы используем в наш текстовый анализ может быть представлен как простые пары ключ-значение, или словари в Pingon lingo. В нашем конкретном случае наши словари массовые, по несколько сотен МБ, и к ним нужно постоянно обращаться. Фактически для данного HTTP-запроса можно получить доступ к 4 или 5 моделям, каждый из которых выполняет поиск по 20-30. Таким образом, проблема, с которой мы сталкиваемся, заключается в том, как мы можем быстро и быстро поддерживать клиента, а также как можно больше света для сервера.

...

Я нашел этот пакет, marisa пытается, который представляет собой оболочку Python вокруг реализации C ++ для marisa. «Marisa» является аббревиатурой для алгоритма соответствия с рекурсивно реализованным StorAge. Что замечательно в попытках мариссы - механизм хранения действительно сокращает количество памяти, в которой вы нуждаетесь. Автор плагина Python утверждал, что размер 50-100X меньше - наш опыт аналогичен.

Что отличает нас от пакета marisa trie, так это то, что базовая структура trie может быть записана на диск, а затем читать через объект с отображением памяти. С памятью marisa trie, все наши требования теперь выполнены. Использование памяти в нашем сервере резко сократилось примерно на 40%, и наша производительность не изменилась с того момента, когда мы использовали реализацию словаря Python.

Существует также несколько реализаций с использованием чистого питона, вы находитесь на ограниченной платформе, для которой вы хотите использовать вышеприведенную реализацию C ++, для лучшей производительности:

20
ответ дан Anentropic 24 August 2018 в 10:28
поделиться

Изменено по методу senderle (см. выше). Я обнаружил, что defaultdict Python идеально подходит для создания дерева trie или префикса.

from collections import defaultdict

class Trie:
    """
    Implement a trie with insert, search, and startsWith methods.
    """
    def __init__(self):
        self.root = defaultdict()

    # @param {string} word
    # @return {void}
    # Inserts a word into the trie.
    def insert(self, word):
        current = self.root
        for letter in word:
            current = current.setdefault(letter, {})
        current.setdefault("_end")

    # @param {string} word
    # @return {boolean}
    # Returns if the word is in the trie.
    def search(self, word):
        current = self.root
        for letter in word:
            if letter not in current:
                return False
            current = current[letter]
        if "_end" in current:
            return True
        return False

    # @param {string} prefix
    # @return {boolean}
    # Returns if there is any word in the trie
    # that starts with the given prefix.
    def startsWith(self, prefix):
        current = self.root
        for letter in prefix:
            if letter not in current:
                return False
            current = current[letter]
        return True

# Now test the class

test = Trie()
test.insert('helloworld')
test.insert('ilikeapple')
test.insert('helloz')

print test.search('hello')
print test.startsWith('hello')
print test.search('ilikeapple')
10
ответ дан dapangmao 24 August 2018 в 10:28
поделиться
from collections import defaultdict

Определить Trie:

_trie = lambda: defaultdict(_trie)

Создать Trie:

trie = _trie()
for s in ["cat", "bat", "rat", "cam"]:
    curr = trie
    for c in s:
        curr = curr[c]
    curr.setdefault("_end")

Поиск:

def word_exist(trie, word):
    curr = trie
    for w in word:
        if w not in curr:
            return False
        curr = curr[w]
    return '_end' in curr

Тест:

print(word_exist(trie, 'cam'))
0
ответ дан DingLi 24 August 2018 в 10:28
поделиться

Эта версия использует рекурсию

import pprint
from collections import deque

pp = pprint.PrettyPrinter(indent=4)

inp = raw_input("Enter a sentence to show as trie\n")
words = inp.split(" ")
trie = {}


def trie_recursion(trie_ds, word):
    try:
        letter = word.popleft()
        out = trie_recursion(trie_ds.get(letter, {}), word)
    except IndexError:
        # End of the word
        return {}

    # Dont update if letter already present
    if not trie_ds.has_key(letter):
        trie_ds[letter] = out

    return trie_ds

for word in words:
    # Go through each word
    trie = trie_recursion(trie, deque(word))

pprint.pprint(trie)

Выход:

Coool                  
2
ответ дан naren 24 August 2018 в 10:28
поделиться

Если вы хотите, чтобы TRIE реализован как класс Python, вот что я написал после прочтения о них:

class Trie:

    def __init__(self):
        self.__final = False
        self.__nodes = {}

    def __repr__(self):
        return 'Trie<len={}, final={}>'.format(len(self), self.__final)

    def __getstate__(self):
        return self.__final, self.__nodes

    def __setstate__(self, state):
        self.__final, self.__nodes = state

    def __len__(self):
        return len(self.__nodes)

    def __bool__(self):
        return self.__final

    def __contains__(self, array):
        try:
            return self[array]
        except KeyError:
            return False

    def __iter__(self):
        yield self
        for node in self.__nodes.values():
            yield from node

    def __getitem__(self, array):
        return self.__get(array, False)

    def create(self, array):
        self.__get(array, True).__final = True

    def read(self):
        yield from self.__read([])

    def update(self, array):
        self[array].__final = True

    def delete(self, array):
        self[array].__final = False

    def prune(self):
        for key, value in tuple(self.__nodes.items()):
            if not value.prune():
                del self.__nodes[key]
        if not len(self):
            self.delete([])
        return self

    def __get(self, array, create):
        if array:
            head, *tail = array
            if create and head not in self.__nodes:
                self.__nodes[head] = Trie()
            return self.__nodes[head].__get(tail, create)
        return self

    def __read(self, name):
        if self.__final:
            yield name
        for key, value in self.__nodes.items():
            yield from value.__read(name + [key])
3
ответ дан Noctis Skytower 24 August 2018 в 10:28
поделиться

Вот список пакетов python, которые реализуют Trie:

  • marisa-trie - реализация на основе C ++.
  • python-trie - простая реализация чистого python.
  • PyTrie - более совершенная реализация чистого python.
12
ответ дан Tzach 24 August 2018 в 10:28
поделиться

Нет «нужно»; тебе решать. Различные реализации будут иметь разные характеристики производительности, занимать различное количество времени, чтобы реализовать, понять и получить право. Это, по-моему, типично для разработки программного обеспечения в целом.

Возможно, я сначала попытался бы иметь глобальный список всех трёх узлов, которые до сих пор были созданы, и представлять дочерние указатели в каждом узле в виде списка индексов в глобальный список. Наличие словаря для представления привязки ребенка для меня слишком тяжело.

10
ответ дан unwind 24 August 2018 в 10:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: