我正在尝试计算一个数字的因子,给出素数,例如:
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}
我正在使用reduce和声明内部步骤函数,但似乎代码可能更清晰。我很感激有关如何使代码更具惯用性的任何建议。
(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 - 感谢您的代码。我习惯于命令式编程,所以我在Groovy中重写了你的例子,以了解它正在做什么。 findFactorsInject()方法使用Groovy的inject()方法,该方法相当于Clojure中的reduce。
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))
}
答案 0 :(得分:4)
考虑将代码分解为3个函数来构成
但你可以一起做到这一点
(defn factors [n primes]
(-> (reduce
(fn [[a n] p]
(if (zero? (rem n p))
(recur [(concat a (map #(* p %) a)) (quot n p)] p)
[a n]))
[[1] n] primes)
first set))
(factors 1176 [2 3 5 7])
;=> #{7 1 24 4 21 1176 294 56 168 196 6 28 588 3 12 2 14 392 98 147 42 8 49 84}
答案 1 :(得分:2)
......或者,严重依赖于序列函数:
(defn factors [n primes]
(set
(reduce
(fn [xs ys] (for [x xs, y ys] (* x y)))
[1]
(map
(fn [p] (take-while #(zero? (mod n %)) (iterate #(* p %) 1)))
primes))))
例如,
(factors 1176 [2 3 5 7])
; #{1 2 98 3 4 196 6 294 7 8 168 392 42 12 588 14 49 147 84 21 24 56 1176 28}
如果我们命名函数并使用->>
线程宏,这可能更容易阅读:
(defn factors [n primes]
(letfn [(products [xs ys] (for [x xs, y ys] (* x y)))
(factor-powers [p] (take-while #(zero? (mod n %)) (iterate #(* p %) 1)))]
(->> primes
(map factor-powers)
(reduce products [1])
set)))
...产生与以前相同的结果:
(factors 1176 [2 3 5 7])
; #{1 2 98 3 4 196 6 294 7 8 168 392 42 12 588 14 49 147 84 21 24 56 1176 28}
答案 2 :(得分:1)
我不确定我是否完全理解您的问题但是
(find-factors 1176 #{147 })
;user=> (147 294 588 1176)
然后这个工作
(defn find-factors [n c]
(->> n
((comp rest range inc) )
(remove #(ratio? (/ n %)))
(#(for [x c
y %
:when (not (ratio? (/ y x)))]
y ))))