查找最接近给定值的密钥,用于clojure排序映射

时间:2009-12-30 19:07:00

标签: data-structures clojure

对于clojure的排序映射,如何找到具有最接近给定值的键的条目?

e.g。假设我有

(def my-map (sorted-map 
                      1 A 
                      2 B
                      5 C))

我想要像

这样的功能
(find-closest my-map 4)

将返回(5,C),因为那是具有最近密钥的条目。我可以做一个线性搜索,但由于地图已经排序,应该有一种方法可以找到像O(log n)这样的值。

我在API中找不到任何可以实现此功能的内容。例如,如果我可以在地图中询问第i个条目,我可以拼凑一个类似我想要的函数,但我找不到任何这样的函数。

修改

显然,sorted-map基于java中实现的PersistentTreeMap类,它是一个红色和黑色的树。所以这看起来应该是可行的,至少在原则上是这样。

3 个答案:

答案 0 :(得分:13)

subseq和rsubseq非常快,因为它们利用树结构:

(def m (sorted-map 1 :a, 2 :b, 5 :c)) 

(defn abs [x] (if (neg? x) (- x) x))
(defn find-closest [sm k]
  (if-let [a (key (first (rsubseq sm <= k)))]
    (if (= a k)
      a
      (if-let [b (key (first (subseq sm >= k)))]
        (if (< (abs (- k b)) (abs (- k a)))
          b
          a)))
    (key (first (subseq sm >= k)))))

user=> (find-closest m 4)
5
user=> (find-closest m 3)
2

这比理想工作略多,在理想情况下我们只需要进行&lt; =搜索,然后查看右边的节点,检查是否有更接近该方向的信息。您可以访问树(.tree m),但.left和.right方法不公开,因此目前无法进行自定义遍历。

答案 1 :(得分:1)

使用Clojure contrib库data.avl。它支持具有最近函数的排序映射和其他有用的功能。

https://github.com/clojure/data.avl

答案 2 :(得分:0)

我想到的第一件事就是将地图的键拉出到矢量中,然后在其中进行二分搜索。如果与您的密钥没有完全匹配,则二进制搜索中涉及的两个指针将最终指向其两侧的两个元素,然后您可以在单个(可能是平局中断)操作中选择更接近的一个。