Project Euler #9 (Pythagorean triplets) in Clojure - clojure

My answer to this problem feels too much like these solutions in C.
Does anyone have any advice to make this more lispy?
(use 'clojure.test)
(:import 'java.lang.Math)
(with-test
(defn find-triplet-product
([target] (find-triplet-product 1 1 target))
([a b target]
(let [c (Math/sqrt (+ (* a a) (* b b)))]
(let [sum (+ a b c)]
(cond
(> a target) "ERROR"
(= sum target) (reduce * (list a b (int c)))
(> sum target) (recur (inc a) 1 target)
(< sum target) (recur a (inc b) target))))))
(is (= (find-triplet-product 1000) 31875000)))

The clojure-euluer-project has several programs for you to reference.

I personally used this algorithm(which I found described here):
(defn generate-triple [n]
(loop [m (inc n)]
(let [a (- (* m m) (* n n))
b (* 2 (* m n)) c (+ (* m m) (* n n)) sum (+ a b c)]
(if (>= sum 1000)
[a b c sum]
(recur (inc m))))))
Seems to me much less complicated :-)

Related

Why is this lazy-sequence not printing?

I cannot figure out why this lazy-sequence is not printing. I've looked at other posts on here (such as this) and none seem to be exactly what I am looking for. Here is the code segment...
(defn exp [x n]
(reduce * (repeat n x))
)
(defn primes
([] (primes 1 1))
([n m] (if (= n 1) (lazy-seq (cons (* (exp 7 n) (exp 11 m)) (primes (+ m 1) (1))))
(lazy-seq (cons (* (exp 7 n) (exp 11 m)) (primes (- n 1) (+ m 1)))))
)
)
(take 4 (primes))
Any help is greatly appreciated. Thank you!
The three comments really give the answer. But always good to actually see the code, so here are two ways that give the printed output.
(defn exp [x n]
(reduce * (repeat n x)))
(defn primes
([] (primes 1 1))
([n m] (if (= n 1)
(lazy-seq (cons (* (exp 7 n) (exp 11 m)) (primes (+ m 1) 1)))
(lazy-seq (cons (* (exp 7 n) (exp 11 m)) (primes (- n 1) (+ m 1)))))))
(defn x-1 []
(doseq [prime (take 4 (primes 2 2))]
(println prime)))
(defn x-2 []
(->> (primes 2 2)
(take 4)
(apply println)))

How to use swap to get result in clojure

I want to write the function collect which can combine the sublists into a list, like:
user=> (collect '(a b c d e) 1)
((a)(b)(c)(d)(e))
user=> (collect '(a b c d e) 2)
((a b)(c d)(e))
user=> (collect '(a b c d e) 5)
(a b c d e))
this is my code:
(defn collect [lst num]
(loop [l lst res (atom ())]
(if (<= (count l) num) #res
(recur (drop num l) (swap! res conj (take num (drop num l)))))))
But when I run
user=> (collect '(a b c d e) 1)
I got the error:
ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.IAtom clojure.core/swap!
why I cannot get the res when I use "swap!" ? Thank you.
It's blowing up in the second pass through the loop.
swap returns the value that was put into the atom, not the atom it's self. So the first pass is updating the atom, and then passing the value it just put into the atom to the second pass through the loop. in the second pass it's trying to use the value as the atom, and getting the exception above.
To "fix" this use a do to update the atom, then pass the atom to the next pass through the loop once it contains the correct value.
user> (defn collect [lst num]
(loop [l lst res (atom ())]
(if (<= (count l) num) #res
(recur (drop num l)
(do (swap! res conj (take num (drop num l)))
res)))))
#'user/collect
user> (collect '(a b c d e) 2)
((e) (c d))
You can also in this case, just remove the atom completely and get exactly the same result (I fixed on ordering problem from your example by using a [] instead of () in the initial value of res):
user> (defn collect [lst num]
(loop [l lst res []]
(if (<= (count l) num) res
(recur (drop num l)
(conj res (take num (drop num l)))))))
#'user/collect
user> (collect '(a b c d e) 2)
[(c d) (e)]
and of course you can also use partition-all as glts mentions above.
;; this would be a correct way to do it
(defn collect [coll n]
(partition-all n coll))
;; this would be a clumsy way to do it
(defn collect
"using a loop (there is not point to do that but at least you can see the logic working as in your example)"
[coll n]
(lazy-seq
(loop [res []
coll coll]
(if (empty? coll)
res
(recur (conj res (take n coll)) (drop n coll))))))
Regarding your error, on the second loop, res is a list-like value, not an atom anymore. That would lead us to :
(defn collect [coll n]
(lazy-seq (loop [res (atom [])
coll coll]
(if (empty? coll)
#res
(recur (do (swap! res conj (take n coll))
;; return the atom instead of the value'
res)
(drop n coll))))))
Note that in order to preserve the order in the solution, I use a vector (litteral []) instead of a list (litteral '()). This is because of the behaviour of conj described here.

NullPointerException using Clojure

I'm new to clojure, attempting to write a function (all-bit-seqs n) that generates all bit strings of length n as a list. So if I were to call (all-bit-seqs 2), it would output ((0 0) (0 1) (1 0) (1 1)) in any order. However, I am getting a NullPointerException when I call the helper function rest-bit-seqs, and I can't figure out why. My code is as follows, any help would be appreciated.
(defn not-bit [x]
(* -1 (- x 1))
)
(defn inc-bit-seq [x]
(cond
(= 0 (not-bit (first x))) (cons 0 (inc-bit-seq (rest x)))
:else (cons 1 (rest x))
)
)
(defn pow [x, y]
(cond
(not= y 0) (* x (pow x (- y 1)))
:else 1
)
)
(defn rest-bit-seqs [n, x, lst]
(cond
(not= x (pow 2 n)) (cons lst (rest-bit-seqs n (+ 1 x) (inc-bit-seq lst)))
:else '()
)
)
(defn zero-seq [n]
(cond
(= n 0) '()
:else (cons 0 (zero-seq (- n 1)))
)
)
(defn all-bit-seqs [n]
(rest-bit-seqs n 0 (zero-seq n))
)
that is because you don't handle the case of an empty sequence here:
(defn inc-bit-seq [x]
(cond
(= 0 (not-bit (first x))) (cons 0 (inc-bit-seq (rest x)))
:else (cons 1 (rest x))
)
)
so at one point you pass (first x) (which is nil for an empty seq) to not-bit.
the following fix solves this:
(defn inc-bit-seq [x]
(when (seq x)
(cond
(= 0 (not-bit (first x))) (cons 0 (inc-bit-seq (rest x)))
:else (cons 1 (rest x))
))
)
in repl:
user> (all-bit-seqs 2)
((0 0) (1 0) (0 1) (1 1))
the other things that are totally weird here, is your choice of cond instead of simple if, and uncommon formatting. I would consider rewriting the code this way:
(defn not-bit [x]
(* -1 (- x 1)))
(defn inc-bit-seq [x]
(when (seq x)
(if (zero? (not-bit (first x)))
(cons 0 (inc-bit-seq (rest x)))
(cons 1 (rest x)))))
(defn pow [x, y]
(if-not (zero? y)
(* x (pow x (- y 1)))
1))
(defn rest-bit-seqs [n, x, lst]
(when-not (== x (pow 2 n))
(cons lst (rest-bit-seqs n (+ 1 x) (inc-bit-seq lst)))))
(defn zero-seq [n]
(when-not (zero? n)
(cons 0 (zero-seq (- n 1)))))
(defn all-bit-seqs [n]
(rest-bit-seqs n 0 (zero-seq n)))
(it's about style, haven't looked at overall code correctness)
Your error is here:
(= 0 (not-bit (first x)))
If x is empty, (first x) will return nil, so this will happen:
(= 0 (not-bit nil))
(= 0 (* -1 (- nil 1))
When you try to evaluate (- nil 1), you'll get a NullPointerException.
The quick-and-dirty way to fix the problem is to get rid of not-bit and replace that condition with
(= 1 (first x))
However, there are much shorter/simpler ways to solve this problem. Here's one way:
(defn inc-bit-seq [[head & tail]]
(if (zero? head)
(cons 1 tail)
(cons 0 (inc-bit-seq tail))))
(defn all-bit-seqs [n]
(take (bit-shift-left 1 n)
(iterate inc-bit-seq (repeat n 0))))
Another way would be to use strings:
(defn pad-first [n x xs]
(concat (repeat (- n (count xs)) x) xs))
(defn all-bit-seqs [n]
(map (comp (partial pad-first n 0)
(partial map #(Character/getNumericValue %))
#(Long/toBinaryString %))
(range (bit-shift-left 1 n))))

Is there mapM/mapM_ in core.async?

I am looking for a function in core.async that does the following:
(map-m #(go (inc %)) (range 5))
; => a channel with one value inside: '(1 2 3 4 5)
A simple (non-lazy) implementation:
; mapM :: Monad m => (a -> m b) -> [a] -> m [b]
(defn map-m [f col]
(go-loop [col col
out []]
(if (seq col)
(recur (rest col)
(conj out (<! (f (first col)))))
out)))
Does the standard core.async API have anything like it?

Trapezoidal Integration is not accurate enough in Clojure

So currently, I wrote a Clojure code to do Trapezoidal integration of a polynomial function in HackerRank.com:
https://www.hackerrank.com/challenges/area-under-curves-and-volume-of-revolving-a-curv
(defn abs[x]
(max x (- 0 x))
)
(defn exp[x n]
(if (> n 0)
(* x (exp x (- n 1)))
1
)
)
(defn fact[x]
(if (> x 0)
(* x (fact (- x 1)))
1)
)
(defn func[x lst1 lst2]
((fn step [sum lst1 lst2]
(if (> (.size lst1) 0)
(step (+ sum (* (last lst1) (exp x (last lst2)))) (drop-last lst1) (drop-last lst2))
sum
)
)
0 lst1 lst2
)
)
(defn integrate[f a b]
(def h 0.001)
(def n (/ (abs (- b a)) h))
((fn step[i sum]
(if (< i n)
(step (+ i 1) (+ sum (f (+ (* i h) a))))
(* h (+ (/(+ (f a) (f b)) 2) sum))
)
) 0 0)
)
(defn volumeIntegral[f a b]
(defn area[r]
(* 3.14159265359 (* r r)))
(def h 0.001)
(def n (/ (abs (- b a)) h))
((fn step[i sum]
(if (< i n)
(step (+ i 1) (+ sum (area (f (+ (* i h) a)))))
(* h (+ (/ (+ (f a) (f b)) 2) sum))
)
) 0 0)
)
(defn lineToVec[line_str] (clojure.string/split line_str #"\s+"))
(defn strToDouble [x] (Double/parseDouble (apply str (filter #(Character/isDigit %) x))))
(defn readline[vec]
((fn step[list vec]
(if (> (.size vec) 0)
(step (conj list (last vec)) (drop-last vec))
list
)
) '() vec)
)
(integrate (fn [x] (func x '(1 2 3 4 5 6 7 8) '(-1 -2 -3 -4 1 2 3 4))) 1 2)
(volumeIntegral (fn [x] (func x '(1 2 3 4 5 6 7 8) '(-1 -2 -3 -4 1 2 3 4))) 1 2)
However, the output I have is:
107.38602491666647
45611.95754801859
While is supposed to be around:
101.4
41193.0
My code passed the first two test cases, but didn't manage to pass the rest. I assume is because of the issue accuracy. I looked through my code several times but couldn't seem to make it better. What am I doing wrong here ? Thank you.
Your exp function isn't quite right -- it doesn't handle negative exponents correctly. Probably best just to use Math/pow.
The other thing you could do is adjust your h value in volumeIntegral but to avoid stack issues, use recur (which gives you tail recursion), e.g. here's a slightly modified version:
(defn volume-integral [f a b]
(defn area[r]
(* Math/PI (* r r)))
(def h 0.000001)
(def n (/ (abs (- b a)) h))
((fn [i sum]
(if (not (< i n))
(* h (+ (/ (+ (f a) (f b)) 2) sum))
(recur (+ i 1) (+ sum (area (f (+ (* i h) a)))))))
0 0))
(I did the something similar with integral.) All in all, I wasn't able to quite hit the second figure, but this should get you on the right track:
101.33517384995224
41119.11576557253