说你要确定哪一个列表里面点是最接近另一个指定点。函数应该返回点本身和距离。
例如用这样的数据:
(def pts [[2 4] [1 9] [9 4] [2 8]])
(def p [7 6])
首先,需要一些辅助功能:
(def abs js/Math.abs)
(def pow js/Math.pow)
(def sqrt js/Math.sqrt)
(def pow2 #(pow % 2))
(defn distance [p1 p2]
(sqrt (+ (pow2 (abs (- (p1 0) (p2 0))))
(pow2 (abs (- (p1 1) (p2 1)))))))
两个提案
我的第一种方法是以下:
(defn find-closest [p pts]
(->> (map #(vector (distance p %) %) pts)
(reduce (fn [m v]
(if (< (v 0) (m 0))
v
m)))))
(find-closest p pts)
=> [2.8284271247461903 [9 4]] ;; this is a correct result
通过努力使功能更加perfomant我想出了这个第二个版本:
(defn find-closest2 [p pts]
(let [init (first pts)]
(reduce (fn [m v]
(let [d (distance p v)]
(if (< d (m 0))
[d v]
m)))
[(distance p init) init]
(rest pts))))
事实上,后来的功能被证明是相当快(在铬浏览器49测试):
=> (time (dotimes [_ 100000] (find-closest p pts)))
"Elapsed time: 445.720000 msecs"
=> (time (dotimes [_ 100000] (find-closest2 p pts)))
"Elapsed time: 248.900000 msecs"
的说明旁白:没有任何人有一个提示,为什么同样的功能是Clojure中的方法要慢:?
user> (time (dotimes [_ 100000] (find-closest p pts)))
"Elapsed time: 6886.850965 msecs"
user> (time (dotimes [_ 100000] (find-closest2 p pts)))
"Elapsed time: 6574.486679 msecs"
这会慢10倍以上,我觉得很难相信。
问题
不管怎么说,因为我需要一个ClojureScript项目的功能,这里是我的问题:你会如何解决这个问题? find-closest
看起来对我好,但更快的版本find-closest2
看起来有点混乱。有没有更好的方法来做到这一点?