我有以下一些代码可以产生正确的结果:
(ns scratch.core
(require [clojure.string :as str :only (split-lines join split)]))
(defn numberify [str]
(vec (map read-string (str/split str #" "))))
(defn process [acc sticks]
(let [smallest (apply min sticks)
cuts (filter #(> % 0) (map #(- % smallest) sticks))]
(if (empty? cuts)
acc
(process (conj acc (count cuts)) cuts))))
(defn print-result [[x & xs]]
(prn x)
(if (seq xs)
(recur xs)))
(let [input "8\n1 2 3 4 3 3 2 1"
lines (str/split-lines input)
length (read-string (first lines))
inputs (first (rest lines))]
(print-result (process [length] (numberify inputs))))
上面的process
函数以递归方式调用自身,直到序列sticks
为empty?
。
我很想知道我是否可以使用take-while
或其他技术来使代码更简洁?
如果我需要对一个序列做一些工作,直到它是空的,那么我使用递归,但我不能帮助认为有更好的方法。
答案 0 :(得分:2)
您的核心问题可以描述为
将最小的子问题识别为步骤3和4并在其周围放置一个框
(defn cuts [sticks]
(let [smallest (apply min sticks)]
(filter pos? (map #(- % smallest) sticks))))
请注意,sticks
在步骤5和3之间没有变化,cuts
是fn stick-&gt;棒,所以请使用iterate在其周围放置一个框:< / p>
(defn process [sticks]
(->> (iterate cuts sticks)
;; ----- 8< -------------------
这会给出sticks
,(cuts sticks)
,(cuts (cuts sticks))
等无限序列,等等
合并第1步和第2步
(defn process [sticks]
(->> (iterate cuts sticks)
(map count) ;; count each sticks
(take-while pos?))) ;; accumulate while counts are positive
(process [1 2 3 4 3 3 2 1])
;-> (8 6 4 1)
在场景后面,这个算法与你发布的算法几乎没有区别,因为懒惰的seqs是递归的延迟实现。它更具惯用性,更模块化,使用延迟取消,增加了它的表现力。此外,如果木棒是空的,它也不需要传递初始计数并做正确的事情。我希望这就是你要找的东西。
答案 1 :(得分:0)
我认为编写代码的方式是一种非常好的方式。当然,The Little Schema中有很多例子都遵循这种缩减/递归格式。
要替换递归,我通常会寻找一个涉及使用高阶函数的解决方案,在本例中为reduce
。它在开始时用一种排序替换每次迭代的min
次调用。
(defn process [sticks]
(drop-last (reduce (fn [a i]
(let [n (- (last a) (count i))]
(conj a n)))
[(count sticks)]
(partition-by identity (sort sticks)))))
(process [1 2 3 4 3 3 2 1])
=> (8 6 4 1)
我已经通过在排序后对相同的数字进行分组,然后对每个组进行计数并减少计数大小来更改算法以适应reduce。