Compte tenu de ce qui suit ... Comment le transformeriez-vous à cette trie? p>
4 Réponses :
comme une approche générale, voici ce que je ferais: p>
Ce problème se prête très bien à une mise en œuvre récursive. Je viserais cela si possible. P>
Je suis sûr qu'il y a une manière plus jolie (il y avait! Voir la réponse de Brian It c'est mieux):
(defn find-in-trie "Finds a sub trie that matches an item, eg: user=> (find-in-trie '(1 (2) (3 (2))) 3) (3 (2))" [tr item] (first (for [ll (rest tr) :when (= (first ll) item)] ll))) (defn add-to-trie "Returns a new trie, the result of adding se to tr, eg: user=> (add-to-trie nil '(1 2)) (1 (2))" [tr se] (cond (empty? se) tr (empty? tr) (add-to-trie (list (first se)) (rest se)) :else (if-let [st (find-in-trie tr (first se))] (cons (first tr) (cons (add-to-trie st (rest se)) (filter (partial not= st) (rest tr)))) (cons (first tr) (cons (add-to-trie (list (first se)) (rest se)) (rest tr)))))) (def in '((1 2) (1 2 3) (1 2 4 5 9) (1 2 4 10 15) (1 2 4 20 25))) (reduce add-to-trie '(nil) in)
Merci. Il est utile de voir le code pour des problèmes courants pour découvrir les idiomes d'une langue.
Pas de soucis, voir la réponse de Brian, il est plus idiomatique et correct.
Les listes sont très maladroites ici, sans parler d'inefficace. Dans Clojure, il est plus idiomatique d'utiliser des vecteurs et des cartes de hachage et des ensembles le cas échéant. Utilisation de Hash-Maps:
user> (def trie (reduce add-to-trie {} in-tree)) #'user/trie user> trie {1 {2 {4 {20 {25 {:terminal true}}, 10 {15 {:terminal true}}, 5 {9 {:terminal true}}}, 3 {:terminal true}, :terminal true}}} user> (in-trie? trie '(1 2)) true user> (in-trie? trie '(1 2 4)) nil user> (in-trie? trie '(1 2 4 20 25)) true
Une bonne réponse et mettent en évidence que la mienne ignorait de manière incorrecte le problème de sous-chaîne. Je suggérerais une in-tri légèrement différente: (defn in-trie? [Trie X] (: Terminal (TRIE X) FAUX)) User => (en trie? Trie '(1 2 4)) FAUX en fait un vrai prédicat et évite la syntaxe d'épissage.
Peut-être :: terminal code>, dans le cas où nous sommes des séquences de trie-ing avec
: terminal code> dans eux?
J'ai corrigé le bug @gregfooter trouvé. N'hésitez pas à inverser la modification. Contrairement à @Timothypratley, j'ai trouvé votre utilisation de l'épissage de non-épissage utile, car il l'indique comme une opération sur les données - non piégées dans un corps macro.
Voici une solution nettoyée. Cela corrige une méthode complémentaire de Bug Brian car elle dépend actuellement de vous insérant les SEQS dans l'ordre croissant. Il permet également d'interroger le triété par préfixe, qui est un cas d'utilisation commun.
Remarque L'utilisation de la mémoire ici est plus élevée car elle stocke les valeurs dans les nœuds de feuille de la trie afin que vous puissiez effectuer des recherches. P>
(defn add-to-trie [trie x] (assoc-in trie x (merge (get-in trie x) {:val x :terminal true}))) (defn in-trie? [trie x] "Returns true if the value x exists in the specified trie." (:terminal (get-in trie x) false)) (defn prefix-matches [trie prefix] "Returns a list of matches with the prefix specified in the trie specified." (keep :val (tree-seq map? vals (get-in trie prefix)))) (defn build-trie [coll] "Builds a trie over the values in the specified seq coll." (reduce add-to-trie {} coll))
Alors la version de Brian irait bien, je suppose que si vous avez toujours utilisé le même nombre de clés?
Votre définition de préfixe-correspondance code> utilise une fonction
Filtre de carte code>, mais il n'y a pas de ce type dans la bibliothèque standard. J'ai essayé de renverser son ingénieur ce qu'il fait, mais ce n'est pas évident. Pouvez-vous poster sa définition?
Filtre de carte Code> est similaire à
Garder code>, qui se trouve dans la noyau LIB.
J'ai appliqué une solution minimale pour le bogue que vous mentionnez à Réponse de Brian .