Clojure清理内部减速器
我试图计算一个数的因子,给定素数,例如:Clojure清理内部减速器,clojure,Clojure,我试图计算一个数的因子,给定素数,例如: 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和声明内部的step函数,但代码似乎更干净。我很欣赏任何关于如何使代码更地道的建议 (defn mul-all [find-for prod-multiples factors] (let [step (
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和声明内部的step函数,但代码似乎更干净。我很欣赏任何关于如何使代码更地道的建议
(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))))))
-------编辑---------
@韦伯-谢谢你的代码。我习惯于命令式编程,所以我用Groovy重写了您的示例,以了解它在做什么。findFactorInject()方法使用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))
}
static List recurFn(设置a、整数n、整数p){
打印“a$a n$n$p$p”
如果(n%p==0){
a、 addAll(a.collect{Integer it->it*p})
recurFn(a,(整数)(n/p),p);
}否则{
返回[a,n]
}
}
静态findFactors(整数findFor,集合素数){
列表结果=[]
for(素数中的整数素数){
if(result.size()==0){
结果=recurFn([1]作为集合,findFor,prime)
}否则{
结果=recurFn((设置)结果[0],(整数)结果[1],素数)
}
}
返回结果
}
静态FindFactorInject(整数findFor,设置素数){
primes.inject([[1]作为集合,findFor],
{列表累加,整数素数->
recurFn((集合)累加[0],(整数)累加[1],素数)
})
}
静态干管(args){
println findFactors(1176,((套)[2,3,7]套)
println FindFactorInput(1176,((套)[2,3,7]套)
}
考虑将代码分解为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}
。。。或者,严重依赖序列函数:
(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}
我不确定我是否完全理解你的问题,但如果
(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 ))))
谢谢,我编辑了我的条目以显示与Groovy中的代码相同的内容。有什么建议/练习可以让你更好地进行函数式编程吗?@jcheat有一套很好的分级函数式问题。提交自己的解决方案后,您可以跟踪其他用户并查看他们的解决方案。