Siempre puede utilizar una biblioteca de Java para esto, como una de las colecciones en Apache commons. TreeBidiMap implementa java.util.Map
, por lo que incluso puede seq-able sin ningún esfuerzo.
user> (def x (org.apache.commons.collections.bidimap.TreeBidiMap.))
#'user/x
user> (.put x :foo :bar)
nil
user> (keys x)
(:foo)
user> (.getKey x :bar)
:foo
user> (:foo x)
:bar
user> (map (fn [[k v]] (str k ", " v)) x)
(":foo, :bar")
Algunas cosas no funcionarán sin embargo, al igual que assoc
y dissoc
, ya que esperan colecciones persistentes y TreeBidiMap es mutable.
Si realmente quieres hacer esto en Clojure nativo, podrías usar metadatos para mantener el hash de dirección inversa. Esto todavía duplicará los requisitos de memoria y duplicará el tiempo para cada agregar y eliminar, pero las búsquedas serán lo suficientemente rápidas y al menos todo estará incluido.
(defn make-bidi []
(with-meta {} {}))
(defn assoc-bidi [h k v]
(vary-meta (assoc h k v)
assoc v k))
(defn dissoc-bidi [h k]
(let [v (h k)]
(vary-meta (dissoc h k)
dissoc v)))
(defn getkey [h v]
((meta h) v))
Probablemente tenga que implementar muchas otras funciones para obtener una funcionalidad completa, por supuesto. No estoy seguro de cuán factible es este enfoque.
user> (def x (assoc-bidi (make-bidi) :foo :bar))
#'user/x
user> (:foo x)
:bar
user> (getkey x :bar)
:foo
Gracias, eso es útil. Preferiría tener una opción nativa de clojure, por lo que su segunda idea es algo que podría intentar. –