为什么我的Clojure代码运行得这么慢?

为什么我的Clojure代码运行得这么慢?,clojure,Clojure,下面是我对4clojure的回答 我能通过前三次考试,但最后一次考试超时了。在最后一次测试中,代码运行非常非常缓慢。到底是什么原因造成的 ((fn [& coll] (loop [coll coll m {}] (do (let [ct (count coll) ns (mapv first coll) m' (reduce #(update-in %1 [%2] (fnil inc 0)) m ns

下面是我对4clojure的回答

我能通过前三次考试,但最后一次考试超时了。在最后一次测试中,代码运行非常非常缓慢。到底是什么原因造成的

((fn [& coll] (loop [coll coll m {}]
    (do
        (let [ct (count coll)
                ns (mapv first coll)
                m' (reduce #(update-in %1 [%2] (fnil inc 0)) m ns)]
            (println m')
            (if (some #(<= ct %) (mapv m' ns))
                (apply min (map first (filter #(>= (val %) ct) m')))
                (recur (mapv rest coll) m'))))))
 (map #(* % % %) (range)) ;; perfect cubes
 (filter #(zero? (bit-and % (dec %))) (range)) ;; powers of 2
 (iterate inc 20))
((fn[&coll](循环[coll coll m{}]
(做
(让[ct(coll计数)
ns(mapv第一学院)
m'(减少#(在%1[%2]中更新)(fnil inc 0))m ns]
(println m')

(如果这是计算2的幂的一种非常低效的方法:

(filter #(zero? (bit-and % (dec %))) (range))
这基本上是从0到无穷大进行计数,一路上测试每个数字是否是2的幂。序列越深入,调用
rest
的成本越高


考虑到它是测试输入,并且您无法更改它,我认为您需要重新考虑您的方法。您可能只想对具有最小第一个值的序列调用
rest

您正在收集每个迭代
中每个输入的下一个值(mapv rest coll)m')

您的一个输入生成值的速度非常慢,并且非常快地加速到非常高的值:
(filter#(零)(位和%(dec%))(范围))

您的代码大部分时间都是通过递增1并测试位来发现2的幂


您不需要一个包含所有输入和出现次数的映射。您不需要为尚未找到最低值的项找到下一个值。我不会发布解决方案,因为这是一个练习,但在每次迭代中消除最低的不匹配值应该是一个开始。

除了这里的其他好答案外,您正在做的是b数学中的unch,但所有数字都作为对象装箱,而不是用作原语。有很多方法可以更好地做到这一点。

你确定这会返回吗?我怀疑这里的某些内容比那些惰性输入更贪婪。仅供参考,我解决这个问题的方法是6行,根本不使用reduce或hashmaps,并且做的工作更少比这更重要。我不是说吹牛,而是说你的解决方案比问题复杂得多。@noisesmith我不确定——我没有耐心看它是否会。我假设它会作为一个早期测试完成,代码确实通过了,它也使用无限序列(
(范围)(范围0 100 7/6)[2 3 5 7 11 13])
)。请注意,根据问题的定义,它应该返回64,最多应该是44次迭代(最后一个参数是达到该数字所需时间最长的参数)顺便说一句,你为什么要用mapv而不是map?mapv并不懒惰。正确。有一件事可能会对这个练习有所帮助:想象一下你是如何处理卡片的。假设你有一堆排序过的套装,其中有一些卡片丢失了。你看每一堆中的第一张卡片:你需要丢弃什么?这实际上是练习的一部分,而不是OP的代码。我知道这就是为什么我解释说OP必须找到一种方法,而不需要在每次迭代中从每个输入中获取下一个值。仅供参考,我以一种迂回的方式找到了这一点——使用jdk附带的
jstack
工具来查看所有线程都在做什么,这导致了
(范围)
被称为…@noisesmith——你能解释一下你是怎么做到的吗?在我发布这篇文章之前,我一直在用谷歌搜索Clojure库,让我也这么做。我知道了一个contribute.profile库,但它似乎已经过时了,或者至少自从Clojure.contrib被集成后,我找不到它的引用。
jstack
是一个命令line工具,提供jvm进程的PID,它将所有线程的完整堆栈跟踪转储到终端(当然可以通过管道传输到文件或寻呼机)。您还可以查看JDK 1.7.0.40附带的图形化Java任务控制工具+