Im starting to learn Clojure from the scratch and im stucked on my function. Im trying to find the sum of all the multiples of 3 or 5 below 1000. THis is what i did.
(defn suma [x sum]
(cond
(= (/ x 3) 0)(let [sum (+ sum x)])
(= (/ x 5) 0)(let [sum (+ sum x)])))
(defn main[]
(def sum 0)
(def x 3)
(while(< x 1001)
(do
(suma sum x)
(let [x (+ x 1)]))
(str "Total = " sum)))
I tried several things, but i cant figure out what's wrong....
Any help will be apreciated.
Thanks
EDIT:
Fixed, the problem was on the let, it was not updating the value of the data. Here the solution:
(defn suma [x sum]
(cond
(zero? (mod x 3))(alter-var-root #'sum (constantly (+ sum x)))
(zero? (mod x 5))(alter-var-root #'sum (constantly (+ sum x)))))
(defn main[]
(def sum 0)
(def x 3)
(while(< x 1001)
(do
(suma x sum)
(alter-var-root #'x inc)))
(str "TOTAL = " sum))
A simple solution using the sequence library is
(->> (concat
(range 0 1000 3)
(range 0 1000 5))
distinct
(apply +))
If you want to do it in an iterative style, Don't use while, which depends on side effects. Use loop and recur, which effect a primitive form of recursion called tail recursion:
(defn divides? [i j]
(zero? (mod j i)))
(loop [answer 0, n 0]
(if (< n 1000)
(recur
(if (or (divides? 3 n) (divides? 5 n))
(+ answer n)
answer)
(inc n))
answer))
Both the above produce the same answer.
Here is an outline using a more functional style. Of course, there is more than one way to do it (TM). :)
> lein repl
user=> (def data (range 20))
user=> data
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)
user=> (defn is-mul-3? [x] (zero? (mod x 3)))
user=> (mapv is-mul-3? data)
[true false false true false false true false false true false false true false false true false false true false]
user=> (defn is-mul-5? [x] (zero? (mod x 5)))
user=> (mapv is-mul-5? data)
[true false false false false true false false false false true false false false false true false false false false]
user=> (defn is-mul-3-or-5? [x] (or (is-mul-3? x) (is-mul-5? x)))
user=> (mapv is-mul-3-or-5? data)
[true false false true false true true false false true true false true false false true false false true false]
user=> (def only-3s-and-5s (filterv is-mul-3-or-5? data))
user=> only-3s-and-5s
[0 3 5 6 9 10 12 15 18]
user=> (apply + only-3s-and-5s)
78
Update:
Here is a more imperitive version. Clojure values (like in let are usually immutable). You must use an atom if you want something like a
mutable Java variable:
(ns clj.core
(:gen-class))
(defn is-mul-3? [x]
(zero? (mod x 3)))
(defn is-mul-5? [x]
(zero? (mod x 5)))
(defn is-mul-3-or-5? [x]
(or (is-mul-3? x)
(is-mul-5? x)))
(defn sum-3s-and-5s [limit]
(let [cum-sum (atom 0) ]
(doseq [curr-val (range limit)]
(if (is-mul-3-or-5? curr-val)
(swap! cum-sum + curr-val)))
#cum-sum ))
(defn -main [& args]
(println "cumsum = " (sum-3s-and-5s 20))
)
with result:
~/clj > lein run
cumsum = 78
Related
I am trying to make a guess the number game in clojure but I keep getting an error saying I can only recur from tail position
(def n (rand-int 100))
(prn n)
(println "You have 10 guesses :D")
(println "HINT: My number is between 1 and 100")
(dotimes [i 10]
(def guess (read-line))
(if (= guess str(n))
(recur (println "Correct!") (println "Incorrect"))))
(I am new to clojure)
dotimes is used to execute the body for sideeffects that exact amount given; there is no means to break - except throwing
loop (or functions) are recur targets. Next you would have to count down the attempts so you can stop, if the user did not guess it:
(loop [attempts 10]
; ...
(recur (dec attempts)))
There are also other problematic things:
Don't def inside other forms. Use let instead.
str(n) will throw, as it will try to call n (ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn)
recuring with println looks fishy, since println returns always nil
How do you end dotimes? You don't. Try using loop instead. There are a lot of issues with your code but that's a start.
though this is discouraged and counterclojurish to even think of short circuiting the execution this way, it is still totally possible with macros (purely for education and fun)
(defmacro return [& x]
`(list '~'return (do ~#x)))
(defmacro dotimes+ [[i n] & body]
`(loop [~i 0 res# nil]
(cond (and (list? res#) (= '~'return (first res#))) (second res#)
(< ~i ~n) (recur (inc ~i) (do ~#body))
:else res#)))
can be used like this:
user> (dotimes+ [i 10]
(println i)
(if (== i 5) (return :short-circuited)))
;; 0
;; 1
;; 2
;; 3
;; 4
;; 5
:short-circuited
user> (dotimes+ [i 10]
(println i)
(if (== i 5) (return)))
;; 0
;; 1
;; 2
;; 3
;; 4
;; 5
nil
user> (dotimes+ [i 10]
(println i))
;; 0
;; 1
;; 2
;; 3
;; 4
;; 5
;; 6
;; 7
;; 8
;; 9
nil
notice, that it still expects the return macro to be called in tail position (similar to recur in loop macro)
(dotimes+ [x 4]
(println "attempt" (inc x))
(let [answer (read-line)]
(println "answer is:" answer)
(if (= answer "yes")
(return "YEAH!!!")
(println "WRONG!"))))
I'd like to create a hash-map that has n number of key-value pairs created in sets of 3 where the sets do not intersect, e.g. [(34 false) (35 false) (36 false)] && [(24 false) (25 false) (26 false)] -> {34 false 35 false 36 false 24 false 25 false 26 false}
EDIT:
To play/practice with Clojure, I'm attempting to implement an idiomatic version of the battleship board game. I decided to store the battleship coordinates in a hash-map where the keys are coordinates and the values are booleans indicating whether that section of the ship has been hit. The specific piece of code below is supposed to
Select an axis (horizontal or vertical)
Select a coordinate for the bow of the ship
"Build" the rest of the ship (3 coordinates in total) by increasing the x or y value accordingly, e.g. {"10" false "11" false "12" false}. Note the "10" translates into the second row of a matrix, first column.
Note: Before adding the ship to the hash-map of coordinates the new ship coordinates must be checked to ensure that an intersection does not exist. If it does, the ship must be "re-built."
To that end, I've created the code below. It has 2 issues:
Executing the function results in the following exception from the use of the 'acc' accumulator:
clojure.lang.LazySeq cannot be cast to clojure.lang.Associative
The result of the function is not a single hash-map, but rather a list of n hash-maps
Using idiomatic clojure, how can I achieve my goal?
(defn launch
[n]
(loop [cnt n acc {}]
(if (= cnt 0)
acc
(recur
(- cnt 1)
((fn []
(let [axis (rand-int 2)]
(if (= axis 0)
(let [x (rand-int 8) y (rand-int 10)]
(for [k (range 3)]
(assoc acc (str y (+ x k)) false)))
(let [x (rand-int 10) y (rand-int 8)]
(for [k (range 3)]
(assoc acc (str (+ y k) x) false)))))))))))
that's how i would rewrite it:
(defn create-key [axis-val i]
(if axis-val
(str (rand-int 10) (+ (rand-int 8) i))
(str (+ (rand-int 8) i) (rand-int 10))))
(defn launch [n]
(reduce (fn [acc axis]
(reduce #(assoc % (create-key axis %2) false)
acc
(range 3)))
{}
(repeatedly n #(zero? (rand-int 2)))))
in repl:
user> (launch 5)
{"40" false, "07" false, "19" false,
"46" false, "87" false, "47" false,
"41" false, "62" false, "86" false}
or (in case you don't like reduce):
(defn launch [n]
(zipmap (mapcat #(map (partial create-key %) (range 3))
(repeatedly n #(zero? (rand-int 2))))
(repeat false)))
the third variant is to use list comprehension to generate keys:
(defn launch [n]
(zipmap (for [_ (range n)
:let [axis (zero? (rand-int 2))]
i (range 3)]
(create-key axis i))
(repeat false)))
all three of them are idiomatic ones, i guess, so it's up to you to choose one, according to your own preferred programming style.
notice that the resulting keys are shuffled inside the map, because unsorted maps don't preserve order. If it is important, you should use sorted-map
What about your variant, the one generating error is this:
(for [k (range 3)] (assoc acc (str y (+ x k)) false))
it doesn't put all the keys to one map, rather it generates a seq of three items equalling (assoc acc k false):
(let [acc {}]
(for [k (range 3)] (assoc acc k false)))
;;=> ({0 false} {1 false} {2 false})
to do what you want, you use reduce:
(let [acc {}]
(reduce #(assoc %1 %2 false) acc (range 3)))
;;=> {0 false, 1 false, 2 false}
leetwinski has given a more concise answer, but I thought I would post this anyway, since I basically left your structure intact, and this may help you see the error a bit more clearly.
First, I am not sure why you were rebinding acc to the value of an anonymous function call. Your let will happily return a result; so, you should probably do some thinking about why you thought it was necessary to create an anonymous function.
Second, the problem is that for returns a lazy seq, and you are binding this to what you think is a map data structure. This explains why it works fine for cases 0 and 1, but when you use a value of 2 it fails.
Since I don't really fully understand what you're trying to accomplish, here is your original code, modified to work. Disclaimer--this is not really idiomatic and not how I would write it, but I'm posting because it may be helpful to see versus the original, since it actually works.
(defn launch
[n]
(loop [cnt n
acc {}]
(if (= cnt 0)
acc
(recur
(dec cnt)
(into acc
(let [axis (rand-int 2)]
(if (= axis 0)
(let [x (rand-int 8) y (rand-int 10)]
(map #(hash-map (str y (+ x %)) false) (range 3)))
(let [x (rand-int 10) y (rand-int 8)]
(map #(hash-map (str (+ y %) x) false) (range 3))))))))))
In Clojure I want to find the result of multiple reductions while only consuming the sequence once. In Java I would do something like the following:
double min = Double.MIN_VALUE;
double max = Double.MAX_VALUE;
for (Item item : items) {
double price = item.getPrice();
if (price > min) {
min = price;
}
if (price < max) {
max = price;
}
}
In Clojure I could do much the same thing by using loop and recur, but it's not very composable - I'd like to do something that lets you add in other aggregation functions as needed.
I've written the following function to do this:
(defn reduce-multi
"Given a sequence of fns and a coll, returns a vector of the result of each fn
when reduced over the coll."
[fns coll]
(let [n (count fns)
r (rest coll)
initial-v (transient (into [] (repeat n (first coll))))
fns (into [] fns)
reduction-fn
(fn [v x]
(loop [v-current v, i 0]
(let [y (nth v-current i)
f (nth fns i)
v-new (assoc! v-current i (f y x))]
(if (= i (- n 1))
v-new
(recur v-new (inc i))))))]
(persistent! (reduce reduction-fn initial-v r))))
This can be used in the following way:
(reduce-multi [max min] [4 3 6 7 0 1 8 2 5 9])
=> [9 0]
I appreciate that it's not implemented in the most idiomatic way, but the main problem is that it's about 10x as slow as doing the reductions one at at time. This might be useful for lots performing lots of reductions where the seq is doing heavy IO, but surely this could be better.
Is there something in an existing Clojure library that would do what I want? If not, where am I going wrong in my function?
that's what i would do: simply delegate this task to a core reduce function, like this:
(defn multi-reduce
([fs accs xs] (reduce (fn [accs x] (doall (map #(%1 %2 x) fs accs)))
accs xs))
([fs xs] (when (seq xs)
(multi-reduce fs (repeat (count fs) (first xs))
(rest xs)))))
in repl:
user> (multi-reduce [+ * min max] (range 1 10))
(45 362880 1 9)
user> (multi-reduce [+ * min max] [10])
(10 10 10 10)
user> (multi-reduce [+ * min max] [])
nil
user> (multi-reduce [+ * min max] [1 1 1000 0] [])
[1 1 1000 0]
user> (multi-reduce [+ * min max] [1 1 1000 0] [1])
(2 1 1 1)
user> (multi-reduce [+ * min max] [1 1 1000 0] (range 1 10))
(46 362880 1 9)
user> (multi-reduce [max min] (range 1000000))
(999999 0)
The code for reduce is fast for reducible collections. So it's worth trying to base multi-reduce on core reduce. To do so, we have to be able to construct reducing functions of the right shape. An ancillary function to do so is ...
(defn juxt-reducer [f g]
(fn [[fa ga] x] [(f fa x) (g ga x)]))
Now we can define the function you want, which combines juxt with reduce as ...
(defn juxt-reduce
([[f g] coll]
(if-let [[x & xs] (seq coll)]
(juxt-reduce (list f g) [x x] xs)
[(f) (g)]))
([[f g] init coll]
(reduce (juxt-reducer f g) init coll)))
For example,
(juxt-reduce [max min] [4 3 6 7 0 1 8 2 5 9]) ;=> [9 0]
The above follows the shape of core reduce. It can clearly be extended to cope with more than two functions. And I'd expect it to be faster than yours for reducible collections.
Here is how I would do it:
(ns clj.core
(:require [clojure.string :as str] )
(:use tupelo.core))
(def data (flatten [ (range 5 10) (range 5) ] ))
(spyx data)
(def result (reduce (fn [cum-result curr-val] ; reducing (accumulator) fn
(it-> cum-result
(update it :min-val min curr-val)
(update it :max-val max curr-val)))
{ :min-val (first data) :max-val (first data) } ; inital value
data)) ; seq to reduce
(spyx result)
(defn -main [] )
;=> data => (5 6 7 8 9 0 1 2 3 4)
;=> result => {:min-val 0, :max-val 9}
So the reducing function (fn ...) carries along a map like {:min-val xxx :max-val yyy} through each element of the sequence, updating the min & max values as required at each step.
While this does make only one pass through the data, it is doing a lot of extra work calling update twice per element. Unless your sequence is very unusual, it is probably more efficient to make two (very efficient) passes through the data like:
(def min-val (apply min data))
(def max-val (apply max data))
(spyx min-val)
(spyx max-val)
;=> min-val => 0
;=> max-val => 9
This question already has answers here:
How do I find the index of an item in a vector?
(9 answers)
Closed 8 years ago.
I want to write a program in clojure that would return only the first index value of true values from my function. My code goes here:
(defn func [f x] (map f x))
So, if I give a value like:
(func zero? [1 1 1 0 3 7 0 2])
It gives me:
(false false false true false false true false)
and if I give:
(func (fn [n] (= n 6)) [:cat :dog :six :blorg 6])
It returns:
(false false false false true)
But, what I want is index value of first true. Like for
(func zero? [1 1 1 0 3 7 0 2]) => 3 (desired result)
(func (fn [n] (= n 6)) [:cat :dog :six :blorg 6]) => 4 (desired result)
(func zero? [1 1 3 7 2]) => nil (desired result)
Can anybody suggest how to get the first index value of true?
(count (take-while not '(false false false true false false true false)))
=> 3
(.indexOf '(false true) true)
=> 1
The answer you posted yourself seems slightly overcomplicated. It can be simplified to this:
(defn first-indexed [pred coll]
(first (keep-indexed (fn [idx itm]
(when (pred itm)
idx))
coll)))
i.e. the true? (vec (map part of tun is unnecessary.
Ok, so I found out an answer for my question itself:
(defn indices [pred coll]
(keep-indexed #(when (pred %2) %1) coll))
(defn tun [f x]
(first (indices true?
(vec (map f x)))))
and if you do:
(tun zero? [1 1 3 7 2]) => nil (the exact desired result)
When I use if-let like
(if-let [a 2 b nil] (+ a b))
I get an IllegalArgumentException:
clojure.core/if-let requires exactly 2 forms in binding vector...
Similar for when-let...
This is not what I would expect. If-let could try all bindings and break when one fails and evaluate the else expression.
The same complaint can be found in the comments at clojuredocs. I found an answer here which did not really satisfy since the poster seems to have the equivalent of a nested if-let-structure in mind.
What reasons are there to limit the bindings of the *-let macros?
UPDATE:
As it seems to be unclear, what my expectations of if-let are:
It should evaluate all bindings sequentially.
When all succeed, it should evaluate the 'then'-case.
If one binding fails it should immediately break and evaluate the 'else'-case.
In case of failure the bindings, even succeeded ones, should not be available in the 'else'-expression
Try this out:
(defmacro if-let-multi
([bindings then-exp]
(let [values (take-nth 2 (rest bindings))]
`(if (and ~#values) (let ~bindings ~then-exp) false)))
([bindings then-exp else-exp]
(let [values (take-nth 2 (rest bindings))]
`(if (and ~#values) (let ~bindings ~then-exp) ~else-exp))))
Here it is in action:
user> (if-let-multi [a 2 b nil] (+ a b))
false
user> (if-let-multi [a 2 b 3] (+ a b))
5
user> (if-let-multi [a 2 b nil] (+ a b) "NO WAY")
"NO WAY"
if-let and let serve different purposes and if-let is not just a more restricted version of let. of instance if-let differs from let in that the value is bound only for the then clause and not the else.
user> (if-let [ans (+ 1 2 3)] ans :foo)
6
user> (if-let [ans (+ 1 2 3)] ans ans)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: ans in this context, compiling:(NO_SOURCE_PATH:1)
user> (let [ans (+ 1 2 3)] ans ans)
6
if-let is intended to make life easier in the case where you are binding a value simply to test and use it.
Try this out.
(defmacro if-lets
([bindings true-expr] `(if-lets ~bindings ~true-expr nil))
([bindings true-expr false-expr]
(cond
(or (not (seq bindings)) (not (zero? (rem (count bindings) 2))))
`(throw (IllegalArgumentException. "if-lets requires 2 or multiple of 2 forms in binding vector in user:1"))
(seq (drop 2 bindings))
`(if-let ~(vec (take 2 bindings))
(if-lets ~(vec (drop 2 bindings))
~true-expr
~false-expr)
~false-expr)
:else
`(if-let ~(vec bindings)
~true-expr
~false-expr))))
This macro passed these tests below.
(deftest ut-if-lets
(testing "if-lets macro (normal cases)"
(is (= 0 (if-lets [x 0] x)))
(is (= 0 (if-lets [x 0] x 1)))
(is (= 1 (if-lets [x nil] x 1)))
(is (= 0 (if-lets [x 0 y x] y)))
(is (= 0 (if-lets [x 0 y x] y 1)))
(is (= 1 (if-lets [x nil y x] y 1)))
(is (= 0 (if-lets [x 0 y x z y] z)))
(is (= 0 (if-lets [x 0 y x z y] z 1)))
(is (= 1 (if-lets [x nil y x z y] y 1)))
(is (= true (if-lets [x true] true false)))
(is (= false (if-lets [x false] true false)))
(is (= true (if-lets [x true y true] true false)))
(is (= false (if-lets [x false y true] true false)))
(is (= false (if-lets [x true y false] true false)))
(is (= true (if-lets [x true y true z true] true false)))
(is (= false (if-lets [x false y true z true] true false)))
(is (= false (if-lets [x true y false z true] true false)))
(is (= false (if-lets [x true y true z false] true false)))
)
)
(deftest ut-if-lets-ab
(testing "if-lets macro (abnormal cases)"
(is (= (try (if-lets [] true false) (catch Exception e (.getMessage e)))
"if-lets requires 2 or multiple of 2 forms in binding vector in user:1"))
(is (= (try (if-lets [x] true false) (catch Exception e (.getMessage e)))
"if-lets requires 2 or multiple of 2 forms in binding vector in user:1"))
(is (= (try (if-lets [x true y] true false) (catch Exception e (.getMessage e)))
"if-lets requires 2 or multiple of 2 forms in binding vector in user:1"))
)
)