Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 在列表中查找距离另一点最近的点_Clojure_Clojurescript - Fatal编程技术网

Clojure 在列表中查找距离另一点最近的点

Clojure 在列表中查找距离另一点最近的点,clojure,clojurescript,Clojure,Clojurescript,导言 假设您想确定列表中最接近另一个给定点的点。函数应该返回点本身和距离 例如,使用此数据: (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 (-

导言

假设您想确定列表中最接近另一个给定点的点。函数应该返回点本身和距离

例如,使用此数据:

(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
请注意:有人有没有提示,为什么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-closest2
对我来说看起来不错,但是更快的版本
find-closest2
看起来有点混乱。有没有更好的办法

与所有基于微观基准做出决策的情况一样,值得使用基准库,例如,确保看到统计上显著的结果

在这种情况下,区别在于计算立即丢弃的中间惰性序列<代码>映射生成所有可能答案的序列,并为每个答案分配内存。因为您对使用中介结果不感兴趣,所以这段时间是浪费的,并且您的仅reduce版本更快

直到最近,Clojure程序有时不得不在使用map reduce filter等实现简单和可组合与不产生中间结果的快速之间做出选择。这是用修复的,所以现在您可以在不引入中间结果的情况下使用map版本,并且可以以非常通用和适应性强的方式进行

user> (import '[java.lang.Math])
nil
user> (def pow2 #(Math/pow % 2))
      (defn distance [p1 p2]
       (Math/sqrt (+ (pow2 (Math/abs (- (p1 0) (p2 0))))
                  (pow2 (Math/abs (- (p1 1) (p2 1)))))))
#'user/pow2
#'user/distance
user> (defn closer-point
        ([] [Long/MAX_VALUE [Long/MAX_VALUE Long/MAX_VALUE]])
        ([p1] p1)
        ([[distance1 point1 :as p1]
          [distance2 point2 :as p2]]
         (if (< distance1 distance2)
           p1
           p2)))
#'user/closer-point
user> (transduce (map #(vector (distance p %) %))
                 closer-point
                 pts)
[2.8284271247461903 [9 4]]
user>(导入“[java.lang.Math]”)
无
用户>(def pow2#(数学/pow%2))
(定义距离[p1 p2]
(数学/sqrt(+pow2(数学/abs(-(p1 0)(p2 0)))
(pow2(数学/abs(-(第11页)(第21页()()))))
#'用户/pow2
#'用户/距离
用户>(定义接近点)
([]长/最大值[长/最大值长/最大值])
([p1]p1)
([[distance1 point1:as p1]
[距离2点2:作为p2]]
(如果((转换(映射#)(向量(距离p%)%)
更近的点
(临时秘书处)
[2.8284271247461903 [9 4]]

最小键功能就是针对这个问题设计的。这是JVM版本。请注意,我们只需最小化平方距离,而不用麻烦使用
Math/sqrt
计算实际距离:

(ns clj.core
  (:use tupelo.core)
  (:require [clojure.core       :as clj]
            [schema.core        :as s]
            [tupelo.types       :as tt]
            [tupelo.schema      :as ts]
            [criterium.core     :as crit]
  ))

; Prismatic Schema type definitions
(s/set-fn-validation! true)   ; #todo add to Schema docs

(def pts [[2 4] [1 9] [9 4] [2 8]])
(def p [7 6])

(defn square [x] (* x x))

(defn dist2 [p1 p2]
  (+ (square (- (p1 0) (p2 0)))
     (square (- (p1 1) (p2 1)))))

(doseq [curr-p pts]
  (println "curr-p: " curr-p " -> " (dist2 p curr-p)))

(newline)
(spyx (apply min-key #(dist2 p %) pts))

(newline)
(crit/quick-bench (apply min-key #(dist2 p %) pts))

(defn -main [] )
我不会太担心代码的过早优化,只要先让它简单易懂就行了。使用内置函数几乎总是一个很好的开始(当你不需要平方根的时候,只需要最小化一个量的平方就是一个很好的开始)。请注意,我还取消了
(abs…
调用,因为
(square…
会自动执行该操作

以下是运行的结果:

curr-p:  [2 4]  ->  29
curr-p:  [1 9]  ->  45
curr-p:  [9 4]  ->  8
curr-p:  [2 8]  ->  29

(apply min-key (fn* [p1__8701#] (dist2 p p1__8701#)) pts) => [9 4]

WARNING: Final GC required 7.5524163302816705 % of runtime
Evaluation count : 1132842 in 6 samples of 188807 calls.
             Execution time mean : 527.711887 ns
    Execution time std-deviation : 3.437558 ns
   Execution time lower quantile : 524.840276 ns ( 2.5%)
   Execution time upper quantile : 531.911280 ns (97.5%)
                   Overhead used : 1.534138 ns
(ns clj.core
  (:use tupelo.core)
  (:require [clojure.core       :as clj]
            [schema.core        :as s]
            [tupelo.types       :as tt]
            [tupelo.schema      :as ts]
            [criterium.core     :as crit]
  ))

; Prismatic Schema type definitions
(s/set-fn-validation! true)   ; #todo add to Schema docs

(def pts [[2 4] [1 9] [9 4] [2 8]])
(def p [7 6])

(defn square [x] (* x x))

(defn dist2 [p1 p2]
  (+ (square (- (p1 0) (p2 0)))
     (square (- (p1 1) (p2 1)))))

(doseq [curr-p pts]
  (println "curr-p: " curr-p " -> " (dist2 p curr-p)))

(newline)
(spyx (apply min-key #(dist2 p %) pts))

(newline)
(crit/quick-bench (apply min-key #(dist2 p %) pts))

(defn -main [] )
curr-p:  [2 4]  ->  29
curr-p:  [1 9]  ->  45
curr-p:  [9 4]  ->  8
curr-p:  [2 8]  ->  29

(apply min-key (fn* [p1__8701#] (dist2 p p1__8701#)) pts) => [9 4]

WARNING: Final GC required 7.5524163302816705 % of runtime
Evaluation count : 1132842 in 6 samples of 188807 calls.
             Execution time mean : 527.711887 ns
    Execution time std-deviation : 3.437558 ns
   Execution time lower quantile : 524.840276 ns ( 2.5%)
   Execution time upper quantile : 531.911280 ns (97.5%)
                   Overhead used : 1.534138 ns