Clojure: doseq function to print range of numbers from the top down - clojure

I am writing an assignment in Clojure which should display a list of prime numbers between 2 inputs: from and to. I managed to do that with this function:
(defn print-top-primes [ from to ]
(doseq
[ i (prime-seq from to) ] ;;prime-seq returns a range of numbers
(println i)
)
)
Which gives the output:
(print-top-primes 50 100)
53
59
61
67
71
73
79
83
89
97
=> nil
However, the assignment specifies that i need the numbers to be printed like this:
(print-top-primes 50 100)
97
89
83
79
73
71
67
61
59
53
Total=732
=> nil
I cannot manage to use doseq to print the numbers from top to bottom.
I also need to add the total of all the primes but I am not sure how this would work as the doseq function does not hold each value of i.
Perhaps I am using the wrong function, however the example in the assignment outputs a:
=> nil
...suggesting that it is a doseq function?
Any help would be really appreciated.
Thanks

Thank you jas,
Looking at your answer helped me come up with an even easier way i think, this is the way i have been taught so i should probably implement it like this:
(defn print-top-primes [ from to ]
(doseq [i (reverse (prime-seq from to))]
(println i))
(printf "Total = %d\n" (reduce + (prime-seq from to)))
)
Giving the correct output!
I am wondering now is there a way to just output the first 10 largest primes, given there was a large number of primes?

One straightforward way would be like:
(defn print-top-primes [from to]
(let [top-primes (reverse (prime-seq from to))
total (apply + top-primes)]
(doseq [i top-primes]
(println i))
(printf "Total = %d\n" total)))
=> (print-top-primes 50 100)
97
89
83
79
73
71
67
61
59
53
Total = 732
nil
If you really want to avoid making three passes through the list of primes (one for reverse, one for apply +, and one for printing), you can try something like:
(defn print-top-primes [from to]
(loop [primes (prime-seq from to)
total 0]
(let [p (last primes)]
(if p
(do (println p)
(recur (butlast primes) (+ total p)))
(printf "Total = %d\n" total)))))
But you would want to verify that it's enough of a performance gain to justify the increased complexity.

Maybe your course is going to mention it next, but in any case I would not use doseq here but loop and recur:
(loop [elements (reverse (range 10))
sum 0]
(if (empty? elements)
sum
(let [[head & tail] elements]
(println head)
(recur tail (+ sum head)))))
Prints:
9
8
7
6
5
4
3
2
1
0
Returns:
45
Instead of returning the value, you can easily write the required Total line and return nil.
The loop macro allows to define accumulators (like sum). I use the [head & tail] notation to destructure the sequence of elements in two parts. The reversed sequence is traversed only once.
[returns nil] ...suggesting that it is a doseq function?
First, doseq is a macro, and second, there are so many ways to return nil that you cannot guess if the example you have is using doseq or not. Whether you have to use doseq or not should be told by the assignment, maybe you are under no obligation to use it.

Related

Clojure - StackOverflowError while iterating over lazy collection

I am currently implementing solution for one of Project Euler problems, namely Sieve of Eratosthenes (https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes), in Clojure. Here's my code:
(defn cross-first-element [coll]
(filter #(not (zero? (rem % (first coll)))) coll))
(println
(last
(map first
(take-while
(fn [[primes sieve]] (not (empty? sieve)))
(iterate
(fn [[primes sieve]] [(conj primes (first sieve)) (cross-first-element sieve)])
[[] (range 2 2000001)])))))
The basic idea is to have two collections - primes already retrieved from the sieve, and the remaining sieve itself. We start with empty primes, and until the sieve is empty, we pick its first element and append it to primes, and then we cross out the multiples of it from the sieve. When it's exhausted, we know we have all prime numbers from below two millions in the primes.
Unfortunately, as good as it works for small upper bound of sieve (say 1000), it causes java.lang.StackOverflowError with a long stacktrace with repeating sequence of:
...
clojure.lang.RT.seq (RT.java:531)
clojure.core$seq__5387.invokeStatic (core.clj:137)
clojure.core$filter$fn__5878.invoke (core.clj:2809)
clojure.lang.LazySeq.sval (LazySeq.java:42)
clojure.lang.LazySeq.seq (LazySeq.java:51)
...
Where is the conceptual error in my solution? How to fix it?
the reason for this is the following: since the filter function in your cross-first-element is lazy, it doesn't actually filter your collection on every iterate step, rather it 'stacks' filter function calls. This leads to the situation that when you are going to actually need the resulting element, the whole load of test functions would be executed, roughly like this:
(#(not (zero? (rem % (first coll1))))
(#(not (zero? (rem % (first coll2))))
(#(not (zero? (rem % (first coll3))))
;; and 2000000 more calls
leading to stack overflow.
the simplest solution in your case is to make filtering eager. You can do it by simply using filterv instead of filter, or wrap it into (doall (filter ...
But still your solution is really slow. I would rather use loop and native arrays for that.
You have (re-)discovered that having nested lazy sequences can sometimes be problematic. Here is one example of what can go wrong (it is non-intuitive).
If you don't mind using a library, the problem is much simpler with a single lazy wrapper around an imperative loop. That is what lazy-gen and yield give you (a la "generators" in Python):
(ns tst.demo.core
(:use demo.core tupelo.test)
(:require [tupelo.core :as t]))
(defn unprime? [primes-so-far candidate]
(t/has-some? #(zero? (rem candidate %)) primes-so-far))
(defn primes-generator []
(let [primes-so-far (atom [2])]
(t/lazy-gen
(t/yield 2)
(doseq [candidate (drop 3 (range))] ; 3..inf
(when-not (unprime? #primes-so-far candidate)
(t/yield candidate)
(swap! primes-so-far conj candidate))))))
(def primes (primes-generator))
(dotest
(is= (take 33 primes)
[2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 ])
; first prime over 10,000
(is= 10007 (first (drop-while #(< % 10000) primes)))
; the 10,000'th prime (https://primes.utm.edu/lists/small/10000.txt)
(is= 104729 (nth primes 9999)) ; about 12 sec to compute
)
We could also use loop/recur to control the loop, but it's easier to read with an atom to hold the state.
Unless you really, really need a lazy & infinite solution, the imperative solution is so much simpler:
(defn primes-upto [limit]
(let [primes-so-far (atom [2])]
(doseq [candidate (t/thru 3 limit)]
(when-not (unprime? #primes-so-far candidate)
(swap! primes-so-far conj candidate)))
#primes-so-far))
(dotest
(is= (primes-upto 100)
[2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97]) )

How do i call a function from given two values in clojure one by one

Hi i am new to clojure i have written this function and there are few errors in it. i have got one function called 'checkFunction' it basically gets one paramtere and returns either true or false.
(defn getList [number1 number2]
(loop for x from number1 to number2
(recur (inc num) (if (checkFunction? x) (concat p [num]) p))))
i want the function above to take two paramters for example if i say 'get List 15 20' it should call check function with 15 16 17 18 19 20 and if checkFunction returns true it should put that number in the vector and return it or print it. so far i have got onto this but i am struggling a bit.
Any help or right direction would be very thankful.
If I understand your question, you're trying to filter a range of numbers according to some predicate. (For the sake of the example I set your check-function? to return true for odd numbers.)
(defn check-function? [n]
(odd? n))
(defn get-list [n1 n2]
(filter check-function? (range n1 (+ 1 n2))))
> (get-list 15 20)
(15 17 19)
If you are also interested in how the loop-recur works, here's a version more like what you were trying to do originally. But I will say that one of the nicest things about clojure is that you rarely have to do this!
(defn get-list-2 [n1 n2]
(loop [src (range n1 (+ 1 n2)) dest []]
(if (empty? src)
dest
(let [n (first src)
src (rest src)
dest (if (check-function? n) (conj dest n) dest)]
(recur src dest)))))
> (get-list-2 15 20)
[15 17 19]

Why do I get an error from this code?

I´m new to clojure and am trying to break through some of the walls I keep running into. The code in question is the function v3 which should accept 4 arguments:
a min and a max integer, mi and ma, to use with the
random-numbers function to find numbers within a certain range,
another integer,cnt, to signify how many numbers I want in my
final list, and
tones, which is a list of integers that the randomized numbers have
to match once I've calculated modulo 12 of said numbers.
The function should run until o is a list of length cnt containing random numbers that are also in the tones list.
My document compiles just fine but when I want to run the function itself in a repl, for example using something like (v3 58 52 15 '(0 2 4 5 7 9)) I get the following error:
ClassCastException clojure.langLazySeq cannot be cast to java.lang.Number clojure.langNumbers.reminder (Numbers.java:173)
Here's my code
(defn random-numbers [start end n]
(repeatedly n #(+ (rand-int (- end start)) start)))
(defn m12 [input]
(mod input 12))
(defn in? [coll elm]
(some #(= elm %) coll))
(defn v3 [ma mi cnt tones]
(let [o '()]
(loop []
(when(< (count o) cnt)
(let [a (m12 (random-numbers mi ma 1))]
(if (in? tones a)
(conj o a)))))
(println o)))
First of all, it is more idiomatic Clojure to type the parentheses on the same line, and not in the "Java"-way.
When I debug your code I see it fails at the call to m12: random-numbers returns a sequence and the call to mod in m12 expects a number.
You can fix this issue by for example taking the first element from the sequence returned by random-numbers:
(defn v3
[ma mi cnt tones]
(let [o '()]
(loop []
(when (< (count o) cnt)
(let [a (m12 (first (random-numbers mi ma 1)))]
(if (in? tones a)
(conj o a)))))
(println o)))
/edit
I am not sure what your code is supposed to be doing, but this did not stop me to make some more changes. If you use a loop, you usually also see a recur to "recur" back to the loop target. Otherwise it does not do much. I added the following things:
a recur to the loop.
The let statement added to the loop vector (starting value).
println statements in the false clause of the if-statement.
Removed the first if-statement that checked the count
Changed list to vector. You would use a list over a vector when you create code structures structure (for example while writing macros).
See:
(defn v3
[ma mi cnt tones]
(loop [o []]
(if (< (count o) cnt)
(let [a (m12 (first (random-numbers mi ma 1)))]
(if (in? tones a)
(recur (conj o a))
(println "a not in tones, o:" o)))
(println "already " cnt "tones generated"))))
If you run (v3 58 52 4 [0 2 4 5 7 9]) (note I changed your 15 for cnt to 4 and changed the list to a vector) a few times you get for example the following output:
a not in tones, o: [4 4]
a not in tones, o: [9 5 5]
a not in tones, o: []
already 4 tones generated
a not in tones, o: [7]
Hope this helps.
I think I see what you are trying to do.
This is an exercise in automatic composition. Your v3 function is intended to generate a sequence of tones
in a range given by min and max.
with tone class drawn from a given set of tone classes (tones)
The m12 function returns the tone class of a tone, so let's call it that:
(defn tone-class [tone]
(mod tone 12))
While we're about it, I think your random-number function is easier to read if we add the numbers the other way round:
(defn random-number [start end]
(+ start (rand-int (- end start))))
Notice that the possible values include start but not end, just as the standard range does.
Apart from your various offences against clojure semantics, as described by #Erwin, there is a problem with the algorithm underlying v3. Were we to repair it (we will), it would generate a sequence of tone classes, not tones. Interpreted as tones, these do not move beyond the base octave, however wide the specified tone range.
A repaired v3
(defn v3 [mi ma cnt tones]
(let [tone-set (set tones)]
(loop [o '()]
(if (< (count o) cnt)
(let [a (tone-class (random-number mi ma))]
(recur (if (tone-set a) (conj o a) o)))
o))))
For a start, I've switched the order of mi and ma to conform with
range and the like.
We turn tones into a set, which therefore works as a
membership function.
Then we loop until the resulting sequence, o, is big enough.
We return the result rather than print it.
Within the loop, we recur on the same o if the candidate a doesn't fit, but on (conj o a) if it does. Let's try it!
(v3 52 58 15 '(0 2 4 5 7 9))
;(4 5 9 7 7 5 7 7 9 7 5 7 4 9 7)
Notice that neither 0 nor 2 appears, though they are in tones. That's because the tone range 52 to 58 maps into tone class range 4 to 10.
Now let's accumulate tones instead of tone classes. We need to move conversion inside the test, replacing ...
(let [a (tone-class (random-number mi ma))]
(recur (if (tone-set a) (conj o a) o)))
... with ...
(let [a (random-number mi ma)]
(recur (if (tone-set (tone-class a)) (conj o a) o)))
This gives us, for example,
(v3 52 58 15 '(0 2 4 5 7 9))
;(53 52 52 52 55 55 55 53 52 55 53 57 52 53 57)
An idiomatic v3
An idiomatic version would use the sequence library:
(defn v3 [mi ma cnt tones]
(let [tone-set (set tones)
numbers (repeatedly #(random-number mi ma))
in-tones (filter (comp tone-set tone-class) numbers)]
(take cnt in-tones)))
This generates the sequence front first. Though you can't tell by looking at the outcome, the repaired version above generates it back to front.
An alternative idiomatic v3
Using the ->> threading macro to capture the cascade of function calls:
(defn v3 [mi ma cnt tones]
(->> (repeatedly #(random-number mi ma))
(filter (comp (set tones) tone-class))
(take cnt)))

Reverse a vector in clojure

Hi I just starting with Clojure and I cannot manage to reverse a vector of integers.
;generate a vector of random integers
(defn generate-rands
[x]
(vector (take x (repeatedly #(rand-int 100))))
)
;vector of integers
(def my-vector (generate-rands 10))
;reverse the vector of integers
(def my-vector-reversed (reverse my-vector))
;main
(defn main-app
[]
(println "My Vector: \t\t\t" my-vector)
(println "My Vector Reversed: \t" my-vector-reversed))
The output is
=> (main-app)
My Vector: [(14 49 29 3 66 7 60 60 34 19)]
My Vector Reversed: [((14 49 29 3 66 7 60 60 34 19))]
nil
#'startingclojure.app/main-app
=> (vector? my-vector-reversed)
false
Can someone kindly explain me why my-vector-reversed is not a vector? And how can I reverse the content of 'my-vector'?
Thanks
Also, it's preferable to use rseq instead of reverse when you work with vector or sorted-map. It has constant time, because they are indexed and can be efficiently walked in either direction.
from reverse's doc:
Returns a seq of the items in coll in reverse order. Not lazy.
reverse turns anything into a seq, meaning, a list. in order to get back a vector you should turn it into a vector:
(into [] (reverse [1 2 3 4])) ; =>[4 3 2 1]
In your case, look at your "my-vector": [(14 49 29 3 66 7 60 60 34 19)] - its a vector containing a single element - a seq. so reversing it wouldnt change anything. you should use the same technique to turn your seq into a vector:
(defn generate-rands
[x]
(into [] (take x (repeatedly #(rand-int 100)))))
reverse function returns always a seq, not a vector. You can again convert the result into a vector with something like: (apply vector (reverse [1 2 3]))

Clojure to remove non-numbers from a string

I have the following code to try to remove non-numbers froma string:
(apply str
(flatten
(map
(fn[x]
(if (number? x) x))
"ij443kj"
)
)
)
But it always returns an empty string instead of "443". Does anyone know what I am doing wrong here and how I can get the desired result?
number? doesn't work that way. It checks the type. If you pass it a character, you'll get back false every time, no matter what the character is.
I'd probably use a regular expression for this, but if you want to keep the same idea of the program, you could do something like
(apply str (filter #(#{\0,\1,\2,\3,\4,\5,\6,\7,\8,\9} %) "abc123def"))
or even better
(apply str (filter #(Character/isDigit %) myString))
There is an even simpler way, use a regular expression:
(.replaceAll "ij443kj" "[^0-9]" "")
get the char's int values...
(map int (apply vector "0123456789"))
-> (48 49 50 51 52 53 54 55 56 57)
then fix it:
(defn my-int
[char]
(- (int char) 48))
now let's try this again, shall we?
(map my-int (apply vector "0123456789"))
-> (0 1 2 3 4 5 6 7 8 9)
and just to get a warm-and-fuzzy that they're integers...
(map #(* % 10) (map my-int (apply vector "0123456789")))
-> (0 10 20 30 40 50 60 70 80 90)
(reduce + (map my-int (apply vector "0123456789")))
-> 45
in case you will handling decimal
#(re-seq #"[0-9\.]+" "ij443kj")