說你要確定哪一個列表裏面點是最接近另一個指定點。函數應該返回點本身和距離。
例如用這樣的數據:
(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
看起來有點混亂。有沒有更好的方法來做到這一點?