I'm trying to calculate factors of a number, given the prime numbers, so for instance:
REPL=> (find-factors 1176 #{2 3 7})
#{7 24 4 21 1176 294 56 168 196 6 28 588 3 12 2 14 392 98 147 42 8 49 84}
I'm using reduce and declaring inner step functions, but it seems like the code could be cleaner. I appreciate any suggestions on how to make the code more idiomatic.
(defn mul-all [find-for prod-multiples factors]
(let [step (fn [[prod-multiples factors] mult]
(let [step2 (fn [[prod-mults factors] mult2]
(let [multiple (* mult mult2)]
(if (zero? (rem find-for multiple))
[(into prod-mults [mult mult2 multiple]) (into factors [multiple])]
[(reduce disj prod-mults [mult mult2]) factors])))]
(reduce step2 [prod-multiples factors] prod-multiples)))]
(reduce step [prod-multiples factors] factors)))
(defn find-factors [find-for prime-factors]
(loop [result (mul-all find-for prime-factors prime-factors)]
(if (zero? (count (first result)))
(second result)
(recur (mul-all find-for (first result) (second result))))))
-------EDIT---------
@A. Webb - Thanks for the code. I'm used to imperative programming, so I rewrote your example in Groovy to understand what it's doing. The findFactorsInject() method uses Groovy's inject() method which is equivalent to reduce in Clojure.
static List recurFn(Set a, Integer n, Integer p ) {
println "a $a n $n p $p"
if(n%p == 0) {
a.addAll(a.collect{Integer it ->it*p})
recurFn(a, (Integer)(n/p), p);
} else {
return [a, n]
}
}
static findFactors(Integer findFor, Set<Integer> primes) {
List result = []
for(Integer prime in primes) {
if(result.size() == 0) {
result = recurFn([1] as Set, findFor, prime)
} else {
result = recurFn((Set)result[0], (Integer)result[1], prime)
}
}
return result
}
static findFactorsInject(Integer findFor, Set<Integer> primes) {
primes.inject ([[1] as Set, findFor],
{ List accumulate, Integer prime ->
recurFn((Set)accumulate[0], (Integer)accumulate[1], prime)
})
}
static main(args) {
println findFactors(1176, ( (Set) [2, 3, 7 ] as Set))
println findFactorsInject(1176, ( (Set) [2, 3, 7 ] as Set))
}