How to split a number in Clojure? - 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)))

Related

Clojure function to Replace Count

I need help with an assignment that uses Clojure. It is very small but the language is a bit confusing to understand. I need to create a function that behaves like count without actually using the count funtion. I know a loop can be involved with it somehow but I am at a lost because nothing I have tried even gets my code to work. I expect it to output the number of elements in list. For example:
(defn functionname []
...
...)
(println(functionname '(1 4 8)))
Output:3
Here is what I have so far:
(defn functionname [n]
(def n 0)
(def x 0)
(while (< x n)
do
()
)
)
(println(functionname '(1 4 8)))
It's not much but I think it goes something like this.
This implementation takes the first element of the list and runs a sum until it can't anymore and then returns the sum.
(defn recount [list-to-count]
(loop [xs list-to-count sum 0]
(if (first xs)
(recur (rest xs) (inc sum))
sum
)))
user=> (recount '(3 4 5 9))
4
A couple more example implementations:
(defn not-count [coll]
(reduce + (map (constantly 1) coll)))
or:
(defn not-count [coll]
(reduce (fn [a _] (inc a)) 0 coll))
or:
(defn not-count [coll]
(apply + (map (fn [_] 1) coll)))
result:
(not-count '(5 7 8 1))
=> 4
I personally like the first one with reduce and constantly.

How to return a lazy sequence from a loop recur with a conditional in Clojure?

Still very new to Clojure and programming in general so forgive the stupid question.
The problem is:
Find n and k such that the sum of numbers up to n (exclusive) is equal to the sum of numbers from n+1 to k (inclusive).
My solution (which works fine) is to define the following functions:
(defn addd [x] (/ (* x (+ x 1)) 2))
(defn sum-to-n [n] (addd(- n 1)))
(defn sum-to-k [n=1 k=4] (- (addd k) (addd n)))
(defn is-right[n k]
(= (addd (- n 1)) (sum-to-k n k)))
And then run the following loop:
(loop [n 1 k 2]
(cond
(is-right n k) [n k]
(> (sum-to-k n k) (sum-to-n n) )(recur (inc n) k)
:else (recur n (inc k))))
This only returns one answer but if I manually set n and k I can get different values. However, I would like to define a function which returns a lazy sequence of all values so that:
(= [6 8] (take 1 make-seq))
How do I do this as efficiently as possible? I have tried various things but haven't had much luck.
Thanks
:Edit:
I think I came up with a better way of doing it, but its returning 'let should be a vector'. Clojure docs aren't much help...
Heres the new code:
(defn calc-n [n k]
(inc (+ (* 2 k) (* 3 n))))
(defn calc-k [n k]
(inc (+ (* 3 k)(* 4 n))))
(defn f
(let [n 4 k 6]
(recur (calc-n n k) (calc-k n k))))
(take 4 (f))
Yes, you can create a lazy-seq, so that the next iteration will take result of the previous iteration. Here is my suggestion:
(defn cal [n k]
(loop [n n k k]
(cond
(is-right n k) [n k]
(> (sum-to-k n k) (sum-to-n n) )(recur (inc n) k)
:else (recur n (inc k)))))
(defn make-seq [n k]
(if-let [[n1 k1] (cal n k)]
(cons [n1 k1]
(lazy-seq (make-seq (inc n1) (inc k1))))))
(take 5 (make-seq 1 2))
;;=> ([6 8] [35 49] [204 288] [1189 1681] [6930 9800])
just generating lazy seq of candidatess with iterate and then filtering them should probably be what you need:
(def pairs
(->> [1 2]
(iterate (fn [[n k]]
(if (< (sum-to-n n) (sum-n-to-k n k))
[(inc n) k]
[n (inc k)])))
(filter (partial apply is-right))))
user> (take 5 pairs)
;;=> ([6 8] [35 49] [204 288] [1189 1681] [6930 9800])
semantically it is just like manually generating a lazy-seq, and should be as efficient, but this one is probably more idiomatic
If you don't feel like "rolling your own", here is an alternate solution. I also cleaned up the algorithm a bit through renaming/reformating.
The main difference is that you treat your loop-recur as an infinite loop inside of the t/lazy-gen form. When you find a value you want to keep, you use the t/yield expression to create a lazy-sequence of outputs. This structure is the Clojure version of a generator function, just like in Python.
(ns tst.demo.core
(:use tupelo.test )
(:require [tupelo.core :as t] ))
(defn integrate-to [x]
(/ (* x (+ x 1)) 2))
(defn sum-to-n [n]
(integrate-to (- n 1)))
(defn sum-n-to-k [n k]
(- (integrate-to k) (integrate-to n)))
(defn sums-match[n k]
(= (sum-to-n n) (sum-n-to-k n k)))
(defn recur-gen []
(t/lazy-gen
(loop [n 1 k 2]
(when (sums-match n k)
(t/yield [n k]))
(if (< (sum-to-n n) (sum-n-to-k n k))
(recur (inc n) k)
(recur n (inc k))))))
with results:
-------------------------------
Clojure 1.10.1 Java 13
-------------------------------
(take 5 (recur-gen)) => ([6 8] [35 49] [204 288] [1189 1681] [6930 9800])
You can find all of the details in the Tupelo Library.
This first function probably has a better name from math, but I don't know math very well. I'd use inc (increment) instead of (+ ,,, 1), but that's just personal preference.
(defn addd [x]
(/ (* x (inc x)) 2))
I'll slightly clean up the spacing here and use the dec (decrement) function.
(defn sum-to-n [n]
(addd (dec n)))
(defn sum-n-to-k [n k]
(- (addd k) (addd n)))
In some languages predicates, functions that return booleans,
have names like is-odd or is-whatever. In clojure they're usually
called odd? or whatever?.
The question-mark is not syntax, it's just part of the name.
(defn matching-sums? [n k]
(= (addd (dec n)) (sum-n-to-k n k)))
The loop special form is kind of like an anonymous function
for recur to jump back to. If there's no loop form, recur jumps back
to the enclosing function.
Also, dunno what to call this so I'll just call it f.
(defn f [n k]
(cond
(matching-sums? n k) [n k]
(> (sum-n-to-k n k) (sum-to-n n)) (recur (inc n) k)
:else (recur n (inc k))))
(comment
(f 1 2) ;=> [6 8]
(f 7 9) ;=> [35 49]
)
Now, for your actual question. How to make a lazy sequence. You can use the lazy-seq macro, like in minhtuannguyen's answer, but there's an easier, higher level way. Use the iterate function. iterate takes a function and a value and returns an infinite sequence of the value followed by calling the function with the value, followed by calling the function on that value etc.
(defn make-seq [init]
(iterate (fn [n-and-k]
(let [n (first n-and-k)
k (second n-and-k)]
(f (inc n) (inc k))))
init))
(comment
(take 4 (make-seq [1 2])) ;=> ([1 2] [6 8] [35 49] [204 288])
)
That can be simplified a bit by using destructuring in the argument-vector of the anonymous function.
(defn make-seq [init]
(iterate (fn [[n k]]
(f (inc n) (inc k)))
init))
Edit:
About the repeated calculations in f.
By saving the result of the calculations using a let, you can avoid calculating addd multiple times for each number.
(defn f [n k]
(let [to-n (sum-to-n n)
n-to-k (sum-n-to-k n k)]
(cond
(= to-n n-to-k) [n k]
(> n-to-k to-n) (recur (inc n) k)
:else (recur n (inc k)))))

clojure performance on badly performing code

I have completed this problem on hackerrank and my solution passes most test cases but it is not fast enough for 4 out of the 11 test cases.
My solution looks like this:
(ns scratch.core
(require [clojure.string :as str :only (split-lines join split)]))
(defn ascii [char]
(int (.charAt (str char) 0)))
(defn process [text]
(let [parts (split-at (int (Math/floor (/ (count text) 2))) text)
left (first parts)
right (if (> (count (last parts)) (count (first parts)))
(rest (last parts))
(last parts))]
(reduce (fn [acc i]
(let [a (ascii (nth left i))
b (ascii (nth (reverse right) i))]
(if (> a b)
(+ acc (- a b))
(+ acc (- b a))))
) 0 (range (count left)))))
(defn print-result [[x & xs]]
(prn x)
(if (seq xs)
(recur xs)))
(let [input (slurp "/Users/paulcowan/Downloads/input10.txt")
inputs (str/split-lines input)
length (read-string (first inputs))
texts (rest inputs)]
(time (print-result (map process texts))))
Can anyone give me any advice about what I should look at to make this faster?
Would using recursion instead of reduce be faster or maybe this line is expensive:
right (if (> (count (last parts)) (count (first parts)))
(rest (last parts))
(last parts))
Because I am getting a count twice.
You are redundantly calling reverse on every iteration of the reduce:
user=> (let [c [1 2 3]
noisey-reverse #(doto (reverse %) println)]
(reduce (fn [acc e] (conj acc (noisey-reverse c) e))
[]
[:a :b :c]))
(3 2 1)
(3 2 1)
(3 2 1)
[(3 2 1) :a (3 2 1) :b (3 2 1) :c]
The reversed value could be calculated inside the containing let, and would then only need to be calculated once.
Also, due to the way your parts is defined, you are doing linear time lookups with each call to nth. It would be better to put parts in a vector and do indexed lookup. In fact you wouldn't need a reversed parts, and could do arithmetic based on the count of the vector to find the item to look up.

Idiomatic way to get every digit of a number

What's the idiomatic way to get each digit of a number and put them into a sequence?
Currently I'm doing
(map #(Integer/parseInt %) (map str ((comp seq str) 123456)))
, which is somewhat ugly...
Any ideas?
(for [n (str 123456)]
(- (byte n) 48))
(map #(Character/getNumericValue %) (str 123456))
I think it's nice to write this with lazy sequences, even if you can't actually use the laziness because you're building it from the "wrong" end:
(defn digits [x]
(rseq (mapv #(rem % 10)
(->> x
(iterate #(quot % 10))
(take-while pos?)))))
If you want, you can write a digits* that doesn't use mapv or rseq, and lazily returns the digits in backwards order.
How about:
(defn digits
[x]
(if (< x 10)
[x]
(conj (digits (quot x 10))
(rem x 10))))
user=>(digits 123456)
[1 2 3 4 5 6]

Generating binary numbers of n digits in clojure

I'd like to generate binary numbers of n digits from 0 to 2^n-1. For example of 3 digits, "000", "001", "010", ..., "111" (0 to 7 in decimal). The way I used is to use java.lang.Integer.toBinaryString() method and add zeros if necessary like the following:
(defn pad-zero [s n]
(str (reduce str (repeat (- n (count s)) "0")) s))
(defn binary-permutation [n]
(map (fn [s] (pad-zero s n))
(map #(Integer/toBinaryString %) (range 0 (Math/pow 2 n)))))
With this code, I can generate what I want like this. For 3 digits:
(binary-permutation 3)
=> ("000" "001" "010" "011" "100" "101" "110" "111")
But this codes look a little verbose.
Aren't there any ways better or more clojure way to do this?
You can simplify the formatting using cl-format from clojure.pprint:
(defn binary-permutation [n]
(map (partial cl-format nil "~v,'0B" n) (range 0 (Math/pow 2 n))))
You may also be interested to know that (Math/pow 2 n) is equivalent to (bit-shift-left 1 n).
Another way to express this would be in term of selections from clojure.math.combinatorics:
(defn binary-permutation [n]
(map (partial apply str) (selections [0 1] n)))
(defn binary-permutation [n]
(for [x (range (Math/pow 2 n))]
(apply str (reverse (take n (map #(bit-and 1 %) (iterate #(bit-shift-right % 1) x)))))))
(defn pad-zero [s n]
(apply str (take-last n (concat (repeat n \0) s))))