clojure“;看,然后说;序列

clojure“;看,然后说;序列,clojure,Clojure,正在解决一些问题以学习clojure。。。下面的代码对于第40次迭代来说已经足够快了,但是在那之后就慢慢停了下来。我将其与其他一些人的解决方案进行了比较,但我并不清楚这为什么会如此缓慢。我尝试使用recur,认为它与循环一样高效(并避免堆栈消耗)。有一件事我不是100%清楚,那就是仅仅使用recur和使用loop recur之间是否有显著的区别。我测试了两种方法,没有发现任何区别 (def data "3113322113") (defn encode-string [data results

正在解决一些问题以学习clojure。。。下面的代码对于第40次迭代来说已经足够快了,但是在那之后就慢慢停了下来。我将其与其他一些人的解决方案进行了比较,但我并不清楚这为什么会如此缓慢。我尝试使用recur,认为它与循环一样高效(并避免堆栈消耗)。有一件事我不是100%清楚,那就是仅仅使用recur和使用loop recur之间是否有显著的区别。我测试了两种方法,没有发现任何区别

(def data "3113322113")

(defn encode-string [data results count]
   (let [prev (first data)
         curr (second data)]
     (cond (empty? data) results
           (not= prev curr)
           (recur (rest data) (str results count prev) 1)
           :else (recur (rest data) results (inc count)))))

(count
 (nth (iterate #(encode-string % "" 1) data) 40 #_50))
我以Bruce Hauman的解决方案为基准,这是一个非常好的例子:

(defn count-encode [x]
  (apply str
         (mapcat 
          (juxt count first)
          (partition-by identity x))))

我意识到在我的解决方案中,我反复迭代非常大的字符串,但我不知道Bruce的速度有多快,因为尽管他没有显式地迭代,分区可能在幕后迭代。

您的版本计算的是

(str "11" (str "22" (str "31" ...)))
(apply str [1 1 2 2 3 1])
它为每两个字符建立一个全新的字符串对象。因为这涉及到在每一步迭代输入和输出字符串中的每个字符,所以您的操作是字符串长度的二次方

您所比较的解决方案是不同的:它构建了一个延迟的整数序列,这是一个线性时间过程。然后,它做了一些类似于

(str "11" (str "22" (str "31" ...)))
(apply str [1 1 2 2 3 1])
这和

(str 1 1 2 2 3 1 ...)
当使用多个参数调用时,
str
,使用StringBuilder以增量的方式高效地构建结果,如果您在每个中间步骤都需要一个完整的字符串对象,则这种优化是不可用的。因此,整个过程是线性时间,而不是二次时间