clojure refactor code from recursion -
i have following bit of code produces correct results:
(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)))) the process function above recursively calls until sequence sticks empty?.
i curious know if have used take-while or other technique make code more succinct?
if ever need work on sequence until empty use recursion can't thinking there better way.
your core problem can described as
- stop if count of sticks zero
- accumulate count of sticks
- subtract smallest stick each of sticks
- filter positive sticks
- go 1.
identify smallest sub-problem steps 3 , 4 , put box around it
(defn cuts [sticks] (let [smallest (apply min sticks)] (filter pos? (map #(- % smallest) sticks)))) notice sticks don't change between steps 5 , 3, cuts fn sticks->sticks, use iterate put box around that:
(defn process [sticks] (->> (iterate cuts sticks) ;; ----- 8< ------------------- this gives infinite seq of sticks, (cuts sticks), (cuts (cuts sticks)) , on
incorporate step 1 , 2
(defn process [sticks] (->> (iterate cuts sticks) (map count) ;; count each sticks (take-while pos?))) ;; accumulate while counts positive (process [1 2 3 4 3 3 2 1]) ;-> (8 6 4 1) behind scene algorithm hardly differs 1 posted, since lazy seqs delayed implementation of recursion. more idiomatic though, more modular, uses take-while cancellation adds expressiveness. doesn't require 1 pass initial count , right thing if sticks empty. hope looking for.
Comments
Post a Comment