How to convert numbers to roman numerals using Clojure? - clojure

I'm new to Clojure and have a problem with my code. I'm trying make a number converter. This is my code:
(defn romanos [numero]
(when (and (< numero 40) (>= numero 10)) (print "X") (romanos (- numero 10)))
(when (= numero 9) (print "IX") (romanos (- numero 9)))
(when (>= numero 5) (print "V") (romanos (- numero 5)))
(when (= numero 4) (print "IV") (romanos (- numero 4)))
(when (and (<= numero 3) (> numero 0)) (print "I") (romanos (- numero 1)))
(when (= numero 0) (print )))

I realize this is likely to be an exercise, in which case this wouldn't be the answer you were looking for, but…
(clojure.pprint/cl-format nil "~#r" 123)
;= "CXXIII"
To print to standard output instead of returning a string, replace the nil with true; pass in a java.io.Writer instance to print to an arbitrary stream.
See the section on Formatted Output of the Common Lisp HyperSpec for further details.

Each of your when statements is running in sequence. 1-8 work fine, but numbers larger than 8 trigger the condition (>= numero 5) and create a second recursive call.
Your eventual solution should use cond instead of when.

I would propose to keep a map of all the valid roman values to their arab values, subtracting a highest one, less then a number in a loop (adding its roman value to result string):
(defn roman [n]
(let [alphabet (sort-by val >
{\I 1 \V 5 \X 10 \L 50
\C 100 \D 500 \M 1000 "IV" 4
"IX" 9 "XL" 40 "XC" 90 "CD" 400
"CM" 900})]
(loop [res "" n n]
(if (zero? n) res
(let [[rom arab] (some #(when (<= (val %) n) %) alphabet)]
(recur (str res rom) (- n arab)))))))

Related

Decimal to Binary Clojure

I'm following this pseudo code to convert decimal to binary recursively.
findBinary(decimal)
if (decimal == 0)
binary = 0
else
binary = decimal % 2 + 10 * (findBinary(decimal / 2)
This is what I have tried:
(defn binary [n]
(loop [res 0]
(if (= n 0)
res
(recur (res (* (+ (mod n 2) 10) (binary (quot n 2)))) )
)
)
)
But I get this error :
ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn user/binary (form-init9002795692676588773.clj:6)
Any ideas how to fix the code to complete the task?
I realize, that this is about the journey and not the result. But to
have it mentioned: Long/toString can give you a string from a number with a wide
variety of radixes.
(Long/toString 123 2)
; → "1111011"
Here's a slightly different approach which allows recur to be used:
(defn find-binary [d]
(loop [ decimal d
digits '() ]
(if (= decimal 0)
(Integer. (clojure.string/join (map str digits)))
(recur (quot decimal 2) (conj digits (mod decimal 2))))))
In the loop we build up a collection of binary digits, adding each new digit at the beginning of the list so that we end up with the digits in the desired order left-to-right in the list. When the terminating condition is reached we convert the collection-of-digits to a collection-of-strings, join the collection of strings together into single string, and convert the string back to an integer.
Your psuedo code can be expressed pretty directly in clojure:
(defn find-binary [decimal]
(if (= decimal 0)
0
(+ (mod decimal 2) (* 10 (find-binary (quot decimal 2))))))
Examples:
user=> (find-binary 1)
1
user=> (find-binary 2)
10
user=> (find-binary 25)
11001
user=> (find-binary 255)
11111111
The error in your version is here:
(recur (res (* (+ (mod n 2) 10) (binary (quot n 2))))
Specifically, the complaint is that you are trying to use res (which has the value 0) as a function.
To be honest, I'm not sure how to do this with loop-recur. When I try it complains about recur not being from the tail position. Perhaps another answer can enlighten us!
Using recur:
;; returns a binary number string of the given decimal number
(defn find-binary [decimal]
(loop [n decimal
res ""]
(if (= n 0)
res
(recur (quot n 2)
(str (mod n 2) res)))))
But without loop:
(defn find-binary [decimal & {:keys [acc] :or {acc ""}}]
(if (= decimal 0)
acc
(find-binary (quot decimal 2) :acc (str (mod decimal 2) acc))))
The original attempt was the following, but it can't go far in the size of decimal:
(defn find-binary [decimal]
(loop [n decimal ;; number to be binarized
res '() ;; collector list
pos 0] ;; position of binary number
(if (= n 0)
(reduce #'+ res) ;; sum up collector list
(recur (quot n 2)
(cons (* (int (Math/pow 10 pos))
(mod n 2))
res)
(+ 1 pos)))))
For large numbers use:

Return an else value when using recur

I am new to Clojure, and doing my best to forget all my previous experience with more procedural languages (java, ruby, swift) and embrace Clojure for what it is. I am actually really enjoying the way it makes me think differently -- however, I have come up against a pattern that I just can't seem to figure out. The easiest way to illustrate, is with some code:
(defn char-to-int [c] (Integer/valueOf (str c)))
(defn digits-dont-decrease? [str]
(let [digits (map char-to-int (seq str)) i 0]
(when (< i 5)
(if (> (nth digits i) (nth digits (+ i 1)))
false
(recur (inc i))))))
(def result (digits-dont-decrease? "112233"))
(if (= true result)
(println "fit rules")
(println "doesn't fit rules"))
The input is a 6 digit number as a string, and I am simply attempting to make sure that each digit from left to right is >= the previous digit. I want to return false if it doesn't, and true if it does. The false situation works great -- however, given that recur needs to be the last thing in the function (as far as I can tell), how do I return true. As it is, when the condition is satisfied, I get an illegal argument exception:
Execution error (IllegalArgumentException) at clojure.exercise.two/digits-dont-decrease? (four:20).
Don't know how to create ISeq from: java.lang.Long
How should I be thinking about this? I assume my past training is getting in my mental way.
This is not answering your question, but also shows an alternative. While the (apply < ...) approach over the whole string is very elegant for small strings (it is eager), you can use every? for an short-circuiting approach. E.g.:
user=> (defn nr-seq [s] (map #(Integer/parseInt (str %)) s))
#'user/nr-seq
user=> (every? (partial apply <=) (partition 2 1 (nr-seq "123")))
true
You need nothing but
(apply <= "112233")
Reason: string is a sequence of character and comparison operator works on character.
(->> "0123456789" (mapcat #(repeat 1000 %)) (apply str) (def loooong))
(count loooong)
10000
(time (apply <= loooong))
"Elapsed time: 21.006625 msecs"
true
(->> "9123456789" (mapcat #(repeat 1000 %)) (apply str) (def bad-loooong))
(count bad-loooong)
10000
(time (apply <= bad-loooong))
"Elapsed time: 2.581750 msecs"
false
(above runs on my iPhone)
In this case, you don't really need loop/recur. Just use the built-in nature of <= like so:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(def true-samples
["123"
"112233"
"13"])
(def false-samples
["10"
"12324"])
(defn char->int
[char-or-str]
(let [str-val (str char-or-str)] ; coerce any chars to len-1 strings
(assert (= 1 (count str-val)))
(Integer/parseInt str-val)))
(dotest
(is= 5 (char->int "5"))
(is= 5 (char->int \5))
(is= [1 2 3] (mapv char->int "123"))
; this shows what we are going for
(is (<= 1 1 2 2 3 3))
(isnt (<= 1 1 2 1 3 3))
and now test the char sequences:
;-----------------------------------------------------------------------------
; using built-in `<=` function
(doseq [true-samp true-samples]
(let [digit-vals (mapv char->int true-samp)]
(is (apply <= digit-vals))))
(doseq [false-samp false-samples]
(let [digit-vals (mapv char->int false-samp)]
(isnt (apply <= digit-vals))))
if you want to write your own, you can like so:
(defn increasing-equal-seq?
"Returns true iff sequence is non-decreasing"
[coll]
(when (< (count coll) 2)
(throw (ex-info "coll must have at least 2 vals" {:coll coll})))
(loop [prev (first coll)
remaining (rest coll)]
(if (empty? remaining)
true
(let [curr (first remaining)
prev-next curr
remaining-next (rest remaining)]
(if (<= prev curr)
(recur prev-next remaining-next)
false)))))
;-----------------------------------------------------------------------------
; using home-grown loop/recur
(doseq [true-samp true-samples]
(let [digit-vals (mapv char->int true-samp)]
(is (increasing-equal-seq? digit-vals))))
(doseq [false-samp false-samples]
(let [digit-vals (mapv char->int false-samp)]
(isnt (increasing-equal-seq? digit-vals))))
)
with result
-------------------------------
Clojure 1.10.1 Java 13
-------------------------------
Testing tst.demo.core
Ran 2 tests containing 15 assertions.
0 failures, 0 errors.
Passed all tests
Finished at 23:36:17.096 (run time: 0.028s)
You an use loop with recur.
Assuming you require following input v/s output -
"543221" => false
"54321" => false
"12345" => true
"123345" => true
Following function can help
;; Assuming char-to-int is defined by you before as per the question
(defn digits-dont-decrease?
[strng]
(let [digits (map char-to-int (seq strng))]
(loop [;;the bindings in loop act as initial state
decreases true
i (- (count digits) 2)]
(let [decreases (and decreases (>= (nth digits (+ i 1)) (nth digits i)))]
(if (or (< i 1) (not decreases))
decreases
(recur decreases (dec i)))))))
This should work for numeric string of any length.
Hope this helps. Please let me know if you were looking for something else :).
(defn non-decreasing? [str]
(every?
identity
(map
(fn [a b]
(<= (int a) (int b)))
(seq str)
(rest str))))
(defn non-decreasing-loop? [str]
(loop [a (seq str) b (rest str)]
(if-not (seq b)
true
(if (<= (int (first a)) (int (first b)))
(recur (rest a) (rest b))
false))))
(non-decreasing? "112334589")
(non-decreasing? "112324589")
(non-decreasing-loop? "112334589")
(non-decreasing-loop? "112324589")

Clojure- Defining a variable inside of a function?

I have this variable, hand, that works just fine when I define it on its own.
(def yourHand
(map
;;fn
#(let [x %]
(cond
;;hearts
(< x 10) (* x -1)
(< x 13) -10
;;diamonds
(< x 23) (* (mod x 13) -1)
(< x 26) -10
;;clubs
(< x 36) (mod x 13)
(< x 39) 10
;;spades
(< x 49) (mod x 13)
(< x 52) 10
))
;;list
(take (rand-int 12) (repeatedly #(+ 1 (rand-int 52))))))
I would like to use this variable in this function here. This works just fine when I define the variable first then just use its name in the function.
(reduce + (vec (map #(let [x %]
(cond
(= x 1) 1
:else 0
))
yourHand)))
The issue arrises when I try to define the variable within the function, like this.
(reduce + (vec (map #(let [x %]
(cond
(= x 1) 1
:else 0
))
(def hand
(map
;;fn
#(let [x %]
(cond
;;hearts
(< x 10) (* x -1)
(< x 13) -10
;;diamonds
(< x 23) (* (mod x 13) -1)
(< x 26) -10
;;clubs
(< x 36) (mod x 13)
(< x 39) 10
;;spades
(< x 49) (mod x 13)
(< x 52) 10
))
;;list
(take (rand-int 12) (repeatedly #(+ 1 (rand-int 52)))))))))
This would not be necessary if not for 2 things. First, I would like to condense this program down to one function if possible (and I think it /is/ possible!). Second, I need to use this variable at another point in my program so I need to be able to reference it somehow.
Anyway, when I try to evaluate the above function, it complains that it doesn't know "how to create ISeq from: clojure.lang.Var". (This is the error: IllegalArgumentException Don't know how to create ISeq from: clojure.lang.Var clojure.lang.RT.seqFrom (RT.java:542)) I'm assuming this means that it doesn't know how to use my variable as a vector... but it seems to use it as a vector just fine when I define my variable outside of the function!
Any advice?
You shouldn't try to def inside of functions. Generally defs are for top-level namespace values; things that won't (normally) change after the namespace is loaded.
Let's refactor the code a bit to get some reusable functions that don't depend on top-level/static namespace values. Instead of (def yourHand ...) we can have a function that generates hands:
(defn deal-hand []
(map
;;fn
#(cond ;; you have a subtle bug here that sometimes returns nil
;;hearts
(< % 10) (* % -1)
(< % 13) -10
;;diamonds
(< % 23) (* (mod % 13) -1)
(< % 26) -10
;;clubs
(< % 36) (mod % 13)
(< % 39) 10
;;spades
(< % 49) (mod % 13)
(< % 52) 10)
;;list
(take (rand-int 12) (repeatedly #(inc (rand-int 52))))))
Then if you still wanted a namespace def, you could get it like this:
(def your-hand (deal-hand))
And we can wrap your reduce in another function that takes a hand:
(defn score-hand [hand] ;; I made a few simplifications here, but logic is the same
(reduce + (mapv #(if (= 1 %) 1 0) hand)))
Now you have two reusable functions that can generate and score hands:
(deal-hand)
=> (-10 -9 -9 -10 -3 7)
(deal-hand)
=> (8 -2 10 -9 1 2 -10 3 nil 5)
(score-hand (deal-hand))
=> 1
If you need to use a hand in other parts of your program, think about how you can structure your functions to take hands as input, and how hands can flow through your program's functions.

how to Replace an Integer with string 20 percent of the time Clojure

I need to replace an integer with a string in clojure but only for 20% of the outputted integers.
(defn factor5 [x]
(if (= (mod x 3) (mod x 5) 0) "BuzzFizz"
(if (= (mod x 5) 0) "buzz"
(if (= (mod x 3) 0) "fizz" x))))
here i have a fizzbuzz program which prints out "fizz" if the number is a multiple of 3 or "buzz" if it is a multiple of 5 and "BuzzFizz" is printed if is a multiple of both. if an integer is neither of the above multiplies the integer gets printed. What i need is to print "Boom" instead of the integer but only for 20% of the integers.
some pseudo code
if(x == int){
print out Boom instead of x only for 20% }
else{
print out x}
I have very limited exprience in clojure as my pseudocode is java based
Please see the Clojure Cheatsheet for a comprehensive listing of functions.
The one you want is rand, and a test like:
(if (< (rand) 0.2) ....)
if you want the decision made randomly you could use one of the rand runctions in an if statement like so:
user> (defn x20% [x]
(if (rand-nth [true false false false false])
"Boom"
x))
#'user/x20%
user> (x20% 5)
5
user> (x20% 5)
5
user> (x20% 5)
"Boom"
user> (x20% 5)
5
there are also rand and rand-int. which you use is somewhat a matter of style and the specifics of your function:
user> (> 2 (rand-int 10))
true
user> (> 2 (rand-int 10))
true
user> (> 2 (rand-int 10))
false
user> (> 0.2 (rand))
true
user> (> 0.2 (rand))
(defn factor-5 [x]
(if (and (number? x) (zero? (rem x 1)))
(if (zero? (rand-int 5))
"Boom"
x)))
This returns the required value rather than printing it.
It tests that its argument is numeric, and - if so - that it is a
whole number value, which could be byte, short, int, ... .
(rand-int 5) chooses randomly from 0, 1, ... 4.

How to split a number in Clojure?

I am looking for a nice method to split a number with n digits in Clojure I have these two methods:
(->> (str 942)
seq
(map str)
(map read-string)) => (9 4 2)
and...
(defn digits [n]
(cons
(str (mod n 10)) (lazy-seq (positive-numbers (quot n 10)))))
(map read-string (reverse (take 5 (digits 10012)))) => (1 0 0 1 2)
Is there a more concise method for doing this type of operation?
A concise version of your first method is
(defn digits [n]
(->> n str (map (comp read-string str))))
... and of your second is
(defn digits [n]
(if (pos? n)
(conj (digits (quot n 10)) (mod n 10) )
[]))
An idiomatic alternative
(defn digits [n]
(->> n
(iterate #(quot % 10))
(take-while pos?)
(mapv #(mod % 10))
rseq))
For example,
(map digits [0 942 -3])
;(nil (9 4 2) nil)
The computation is essentially eager, since the last digit in is the
first out. So we might as well use mapv and rseq (instead of map and reverse) to do it faster.
The function is transducer-ready.
It works properly only on positive numbers.
You could simply do
(map #(Character/digit % 10) (str 942))
EDIT: Adding a function definition
(defn digits [number] (map #(Character/digit % 10) (str number)))
Usage:
(digits 1234)
Note: This is concise, but does use java String and Character classes. An efficient implementation can be written using integer modulo arithmetic, but won't be concise. One such solution similar to Charles' answer would be:
(defn numTodigits
[num]
(loop [n num res []]
(if (zero? n)
res
(recur (quot n 10) (cons (mod n 10) res)))))
Source
I'm not sure about concise, but this one avoids unnecessary inefficiency such as converting to strings and back to integers.
(defn digits [n]
(loop [result (list), n n]
(if (pos? n)
(recur (conj result (rem n 10))
(quot n 10))
result)))
A recursive implementation (could be more efficient and less concise, but it shouldn't matter for reasonable numbers).
(defn digits [n]
(when (pos? n)
(concat (digits (quot n 10))
[(mod n 10)])))
a looping method:
(defn split-numbers [number]
(loop [itr 0 res [] n number]
(if (= n 0)
res
(recur (inc itr) (concat (vector (mod n 10)) res) (int (/ n 10)))
)
)
)
Easiest i could find:
(->> (str n)
seq
(map (comp read-string str)))