Bạn luôn có thể sử dụng thư viện Java cho điều này, như một trong các bộ sưu tập trong Apache commons. TreeBidiMap thực hiện java.util.Map
vì vậy nó thậm chí còn có thể thực hiện mà không cần bất kỳ nỗ lực nào.
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")
Một số điều sẽ không làm việc mặc dù, như assoc
và dissoc
, vì họ mong đợi bộ sưu tập dai dẳng và TreeBidiMap là có thể thay đổi.
Nếu bạn thực sự muốn thực hiện điều này trong Clojure bản địa, bạn có thể sử dụng siêu dữ liệu để giữ hàm băm đảo ngược. Điều này vẫn sẽ tăng gấp đôi yêu cầu bộ nhớ của bạn và tăng gấp đôi thời gian cho mỗi lần thêm và xóa, nhưng tra cứu sẽ đủ nhanh và ít nhất mọi thứ được đóng gói.
(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))
Có thể bạn sẽ phải triển khai một loạt các chức năng khác để có đầy đủ chức năng của khóa học. Không chắc chắn cách tiếp cận khả thi này là như thế nào.
user> (def x (assoc-bidi (make-bidi) :foo :bar))
#'user/x
user> (:foo x)
:bar
user> (getkey x :bar)
:foo
Nguồn
2009-07-26 00:14:39
Cảm ơn, điều đó rất hữu ích. Tôi muốn có một tùy chọn bản địa clojure, vì vậy ý tưởng thứ hai của bạn là một cái gì đó tôi có thể thử. –