12
votes

Clojure: Comment générer une «trie»?

Compte tenu de ce qui suit ... xxx

Comment le transformeriez-vous à cette trie? xxx


0 commentaires

4 Réponses :


1
votes

comme une approche générale, voici ce que je ferais:

  • Écrivez quelques fonctions pour créer une trie et insérer de nouveaux éléments dans une trie.
  • créer une nouvelle trie.
  • Itérate à travers la liste d'entrée et insérez chaque élément dans la trie.

    Ce problème se prête très bien à une mise en œuvre récursive. Je viserais cela si possible.


0 commentaires

1
votes

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)


2 commentaires

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.



10
votes

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


3 commentaires

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 , dans le cas où nous sommes des séquences de trie-ing avec : terminal 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.



16
votes

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))


4 commentaires

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 utilise une fonction Filtre de carte , 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 est similaire à Garder , qui se trouve dans la noyau LIB.


J'ai appliqué une solution minimale pour le bogue que vous mentionnez à Réponse de Brian .