patternMinor
Counting ways to form an amount using coins
Viewed 0 times
countingamountcoinswaysusingform
Problem
This is just a fun little exercise I had to do for a homework once (in Java rather than Clojure though). Basically, the goal is to find the number of different coin stacks you can build with the coins 1,2,5 and 10 to form a number N (I believe a closed form solution for this exists, but this isn't what this is about).
My solution here works, but I'm not quite happy with it:
Anyways, here's my code (by the way, the function is called "fast-iterative" because the exercise was about calculating these values recursively. Which I think is insane due to the branching factor, but whatever):
My solution here works, but I'm not quite happy with it:
- Explicit loop. Not sure how to do away with it though.
- A few functions there that I think should be core functions, but I can't find them.
- Even if they aren't in core, my functions could probably be written somewhat more concisely
Anyways, here's my code (by the way, the function is called "fast-iterative" because the exercise was about calculating these values recursively. Which I think is insane due to the branching factor, but whatever):
(ns test.coin-stacks)
(def maximum (partial reduce max))
(defn shift-vector
"Shifts v one to the left, insert shift-val at the right"
[v shift-val]
(conj (vec (rest v)) shift-val))
(defn update
"Updates ks in m with f applied to ks.
I can't believe I have to write this myself."
[m ks f]
(apply assoc m (interleave ks (map (comp f m) ks))))
(defn fast-iterative-coinstacks
"Returns the number of ways to form a coin stack with a total
value of n with coins"
[n coins]
(let [max-coin (maximum coins)
initial-stacks (apply conj [1] (repeat max-coin 0))]
(loop [stacks initial-stacks iteration 0]
(if-not (< iteration n)
(first stacks)
(recur (shift-vector (update stacks coins (partial +' (stacks 0))) 0)
(inc iteration))))))Solution
How about something like this:
Some explanations:
-
-
the threading macro
-
iterate is a really convenient function that given
-
you can do a lot of things with
(defn shift-vector
"Shifts v one to the left, insert shift-val at the right"
[v shift-val]
(conj (subvec v 1) shift-val))
(defn update-in-all
"Updates ks in m with f applied for each value at k."
[m ks f]
(reduce (fn [m' k] (update-in m' [k] f)) m ks))
(defn fast-iterative-coinstacks
"Returns the number of ways to form a coin stack with a total
value of n with coins"
[n coins]
(let [max-coin (reduce max coins)
initial-stacks (into [1] (repeat max-coin 0))
process-stacks (fn [stacks]
(-> stacks
(update-in-all coins (partial + (first stacks)))
(shift-vector 0)))]
(-> (iterate process-stacks initial-stacks)
(nth n)
first)))Some explanations:
-
update-in works both with vectors and maps, and can update nested values as well,-
the threading macro
-> makes the flow of your code easier to follow,-
iterate is a really convenient function that given
f and x returns a lazy sequence of x, (f x), (f (f x))...-
you can do a lot of things with
reduce!Code Snippets
(defn shift-vector
"Shifts v one to the left, insert shift-val at the right"
[v shift-val]
(conj (subvec v 1) shift-val))
(defn update-in-all
"Updates ks in m with f applied for each value at k."
[m ks f]
(reduce (fn [m' k] (update-in m' [k] f)) m ks))
(defn fast-iterative-coinstacks
"Returns the number of ways to form a coin stack with a total
value of n with coins"
[n coins]
(let [max-coin (reduce max coins)
initial-stacks (into [1] (repeat max-coin 0))
process-stacks (fn [stacks]
(-> stacks
(update-in-all coins (partial + (first stacks)))
(shift-vector 0)))]
(-> (iterate process-stacks initial-stacks)
(nth n)
first)))Context
StackExchange Code Review Q#17973, answer score: 4
Revisions (0)
No revisions yet.