scala – 为什么这个Clojure程序在一个可变数组上工作这么慢?
发布时间:2020-12-16 18:47:27 所属栏目:安全 来源:网络整理
导读:剧透警报,这是代码日第6天的第一部分. 我试图在Clojure和Scala中解决this问题. Scala程序运行正常,并在我的Macbook Air上几秒钟内完成.然而,Clojure版本需要更长的时间.这里有什么问题? (ns adventofcode.day6 (:require [clojure.java.io :as io] [clojure
剧透警报,这是代码日第6天的第一部分.
我试图在Clojure和Scala中解决this问题. Scala程序运行正常,并在我的Macbook Air上几秒钟内完成.然而,Clojure版本需要更长的时间.这里有什么问题? (ns adventofcode.day6 (:require [clojure.java.io :as io] [clojure.string :as string])) (set! *warn-on-reflection* true) (def ^:const grid-size 1000) (defn make-grid [] (let [grid (make-array Long/TYPE grid-size grid-size)] (doseq [i (range grid-size) j (range grid-size)] (aset grid i j -1)) grid)) (defn parse-line [l] (let [[command left-top right-bottom] (-> l (string/replace "turn off" "turn-off") (string/replace "turn on" "turn-on") (string/replace "through " "") (string/split #" ")) parse-coordinates (fn [s] (let [parts (string/split s #",")] (map #(Integer/parseInt %) parts))) [left top] (parse-coordinates left-top) [right bottom] (parse-coordinates right-bottom)] [command left top right bottom])) (defn process-line [grid command left top right bottom] (doseq [i (range left (inc right)) j (range top (inc bottom))] (case command "turn-off" (aset grid i j -1) "turn-on" (aset grid i j 1) "toggle" (aset grid i j (* -1 (aget grid i j))) (throw (Exception. "unrecognized command"))))) (defn count-lights [grid] (reduce + (for [i (range grid-size) j (range grid-size) :let [value (aget grid ^Long i ^Long j)] :when (pos? value)] value))) (defn the-answer [] (with-open [rdr (-> "input-day6.txt" io/resource io/reader)] (let [grid (make-grid)] (doseq [l (line-seq rdr)] (apply process-line grid (parse-line l))) (count-lights grid)))) 编辑:我已经重写了瞬态向量的解决方案,它具有相当不错的性能(Macbook Air上11秒,Macbook Pro上7秒) (ns adventofcode.day6faster (:require [clojure.java.io :as io] [clojure.string :as string])) (set! *warn-on-reflection* true) (def ^:const grid-size 1000) (defn make-grid [] (vec (repeat (* grid-size grid-size) -1))) (defn parse-line [l] (let [[command left-top right-bottom] (-> l (string/replace "turn off" "turn-off") (string/replace "turn on" "turn-on") (string/replace "through " "") (string/split #" ")) parse-coordinates (fn [s] (let [parts (string/split s #",")] (map #(Integer/parseInt %) parts))) [left top] (parse-coordinates left-top) [right bottom] (parse-coordinates right-bottom)] [command left top right bottom])) (defn set-grid! [t-grid grid-size i j v] (let [pos (+ i (* j (dec grid-size)))] (assoc! t-grid pos v))) (defn update-grid! [t-grid grid-size i j f] (let [pos (+ i (* j (dec grid-size)))] (assoc! t-grid pos (f (get t-grid pos))))) (defn process-line [t-grid command left top right bottom] (doseq [i (range left (inc right)) j (range top (inc bottom))] (case command "turn-off" (set-grid! t-grid grid-size i j -1) "turn-on" (set-grid! t-grid grid-size i j 1) "toggle" (update-grid! t-grid grid-size i j (fn [i] (* -1 i))) (throw (Exception. "unrecognized command"))))) (defn count-lights [grid] (count (filter pos? grid))) (defn the-answer [] (with-open [rdr (-> "input-day6.txt" io/resource io/reader)] (let [t-grid (transient (make-grid))] (doseq [l (line-seq rdr)] (apply process-line t-grid (parse-line l))) (count-lights (persistent! t-grid))))) 编辑2:现在有循环,类型提示和单个可变数组.我的Macbook Air上1.5秒! (ns adventofcode.day6singlearray (:require [clojure.java.io :as io] [clojure.string :as string])) (set! *warn-on-reflection* true) (set! *unchecked-math* :warn-on-boxed) (def ^:const grid-size 1000) (defn make-grid [] (let [l (* grid-size grid-size) a (make-array Long/TYPE l)] (loop [i 0] (if (< i l) (do (aset ^longs a i -1) (recur (inc i))) a)))) (defn parse-line [l] (let [[command left-top right-bottom] (-> l (string/replace "turn off" "turn-off") (string/replace "turn on" "turn-on") (string/replace "through " "") (string/split #" ")) parse-coordinates (fn [s] (let [parts (string/split s #",")] (map #(Integer/parseInt %) parts))) [left top] (parse-coordinates left-top) [right bottom] (parse-coordinates right-bottom)] [command left top right bottom])) (defn set-grid! [grid ^long i ^long j v] (let [pos (+ i (* j (dec grid-size)))] (aset ^longs grid pos ^long v))) (defn toggle-grid! [grid ^long i ^long j] (let [pos (+ i (* j (dec grid-size)))] (aset ^longs grid pos ^long (* -1 (aget ^longs grid pos))))) (defn process-line [grid command left top right bottom] (let [operation (case command "turn-off" #(set-grid! grid %1 %2 -1) "turn-on" #(set-grid! grid %1 %2 1) "toggle" #(toggle-grid! grid %1 %2) (throw (Exception. "unrecognized command")))] (loop [^long i left ^long j top] (if (<= i ^long right) (if (<= j ^long bottom) (do (operation i j) (recur i (inc j))) (recur (inc i) top)))))) (defn count-lights [grid] (count (filter pos? grid))) (defn the-answer [] (with-open [rdr (-> "input-day6.txt" io/resource io/reader)] (let [grid (make-grid)] (doseq [l (line-seq rdr)] (apply process-line grid (parse-line l))) (count-lights grid)))) 解决方法
一个Java原始数组对我来说足够好(在便宜的4-yo笔记本电脑上半秒钟).我没有打扰unbox索引.
(set! *unchecked-math* true) (defn turn-off [^ints grid [r1 c1 r2 c2]] (doseq [i (range r1 (inc r2)) k (range (+ c1 (* i 1000)) (+ c2 (* i 1000) 1))] (aset grid k 0))) (defn turn-on [^ints grid [r1 c1 r2 c2]] (doseq [i (range r1 (inc r2)) k (range (+ c1 (* i 1000)) (+ c2 (* i 1000) 1))] (aset grid k 1))) (defn toggle [^ints grid [r1 c1 r2 c2]] (doseq [i (range r1 (inc r2)) k (range (+ c1 (* i 1000)) (+ c2 (* i 1000) 1))] (aset grid k (- 1 (aget grid k))))) (defn count-on [^ints grid] (areduce grid i cnt 0 (+ cnt (aget grid i)))) (defn day06a [] (let [grid (int-array (* 1000 1000))] ; 0-initialized via Java (with-open [rdr (clojure.java.io/reader "input/input06.txt")] (doseq [cmd (line-seq rdr)] (let [v (map #(Integer/parseInt %) (re-seq #"[0-9]+" cmd))] (cond (.startsWith cmd "turn off") (turn-off grid v) (.startsWith cmd "turn on") (turn-on grid v) (.startsWith cmd "toggle") (toggle grid v))))) (count-on grid))) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |