Digits back to number again - clojure

In Clojure it is easy enough to get a list of digits from a number:
user=> (digits 234432)
(2 3 4 4 3 2)
user=> (map type (digits 22))
(java.lang.Long java.lang.Long)
My question is how to go the other way round - how to create a number from a list of digits?
EDIT Good point, here it is:
(defn digits [n]
(->> n str (map (comp read-string str))))
It comes from here

Two ways I can think of:
Using reduce:
boot.user=> (reduce (fn [a b] (+ b (* a 10))) 0 '(1 2 3 4 5))
12345
Using clojure.string/join and Long/parseLong
boot.user=> (Long/parseLong (clojure.string/join '(1 2 3 4 5)))
12345
Note that the behavior of the two ways is not the same if any digit is greater than 9.
If you need support for bigints, you can do this:
boot.user=> (def digits (repeat 100 1))
#'boot.user/digits
boot.user=> digits
(1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
boot.user=> (reduce (fn [a b] (+ b (* a 10))) 0N digits)
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111N
boot.user=> (bigint (clojure.string/join digits))
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111N

also, there is an option to use read-string or (preferably for safety) clojure.edn/read-string, both from core library. The advantage of this, is that you don't have to think about integer overflow and conversion to bigint, reader would do this for you:
user> (clojure.edn/read-string (apply str [1 2 3 4 5]))
12345
user> (clojure.edn/read-string (apply str (repeat 20 1)))
11111111111111111111N
as an additional feature, it supports every clojure's numeric literal:
float:
user> (clojure.edn/read-string (apply str [1 3 \. 2 4]))
13.24
binary:
user> (clojure.edn/read-string (apply str "2r" [1 1 0 1]))
13
hexadecimal:
user> (clojure.edn/read-string (apply str "0x" [\f 2 \e 3]))
62179
arbitrary (base 5 for example):
user> (clojure.edn/read-string (apply str "5r" [1 3 2 4]))
214
and so on.

Related

Does Clojure have a set that remembers insertion order?

Like Java's LinkedHashSet. So instead of this:
(-> #{} (conj 1 2 3 4 5) vec)
=> [1 4 3 2 5]
You get:
(-> ??? (conj 1 2 3 4 5) vec)
=> [1 2 3 4 5]
Not in the core library, but there's this one.
(use 'flatland.ordered.set)
(ordered-set 4 3 1 8 2)
=> #ordered/set (4 3 1 8 2)
(conj (ordered-set 9 10) 1 2 3)
=> #ordered/set (9 10 1 2 3)
(into (ordered-set) [7 6 1 5 6])
=> #ordered/set (7 6 1 5)

Changing 1-3 random index(s) in a sequence to a random value

I would also like the changed value to be random. For example
'(1 2 3 4 5)
one possible output.
'(1 3 3 4 5)
another
'(1 5 5 4 5)
there are more idiomatic ways to do this in clojure. For example this one:
you can generate infinite lazy sequence of random changes to the initial collection, and then just take a random item from it.
(defn random-changes [items limit]
(rest (reductions #(assoc %1 (rand-int (count items)) %2)
(vec items)
(repeatedly #(rand-int limit)))))
in repl:
user> (take 5 (random-changes '(1 2 3 4 5 6 7 8) 100))
([1 2 3 4 5 64 7 8] [1 2 3 4 5 64 58 8] [1 2 3 4 5 64 58 80]
[1 2 3 4 5 28 58 80] [1 2 3 71 5 28 58 80])
user> (nth (random-changes '(1 2 3 4 5 6 7 8) 100) 0)
[1 2 3 64 5 6 7 8]
and you can just take an item at the index you want (so it means collection with index + 1 changes).
user> (nth (random-changes '(1 2 3 4 5 6 7 8) 100) (rand-int 3))
[1 46 3 44 86 6 7 8]
or just use reduce to take the n times changed coll at once:
(defn random-changes [items limit changes-count]
(reduce #(assoc %1 (rand-int (count items)) %2)
(vec items)
(repeatedly changes-count #(rand-int limit))))
in repl:
user> (random-changes [1 2 3 4 5 6] 100 3)
[27 2 33 4 76 6]
also you can just associate all the changes in a vector at once:
(assoc items 0 100 1 200 2 300), so you can do it like that:
(defn random-changes [items limit changes-count]
(let [items (vec items)
rands #(repeatedly changes-count (partial rand-int %))]
(apply assoc items
(interleave (rands (count items))
(rands limit)))))
in repl:
user> (random-changes [1 2 3 4 5 6] 100 3)
[1 65 61 44 5 6]
Figured it out. Decided to go a longer route and make a function.
(defn changeSequence
[sequ x]
(def transsequ (into [] sequ))
(if (> x 0)
(changeSequence (assoc transsequ (rand-int (count transsequ)) (rand-int foo)) (dec x))
(seq sequ)
))

how to remove a particular occurances from sequence clojure

If I have sequence
[1 1 1 1 3 2 4 1]
how can I remove a particular number from that sequence? For example
(remove [1 1 1 1 3 2 4 1] 1) -> [3 2 4]
You can use a set as a predicate to remove, because sets can be called as functions.
(remove #{1} [1 1 1 1 3 2 4 1])
=> (3 2 4)
wrap that in (vec ..) if you need the result to be a vector.
The bonus of that approach is that you could remove many arbitrary values by sticking them in the set. If it's just one, this of course works too:
(remove #(= 1 %) [1 1 1 1 3 2 4 1])

Using Clojure vector to model a 7 card poker hand

I have a vector that represents a 7 card poker hand and I want to find the next hand using the following method:
values are from 0 to 12 and are sorted (e.g. [0 0 7 11 11 12 12])
A valid vector has atmost 4 of one value
The first valid vector is [0 0 0 0 1 1 1]
If the values at index and index + 1 are different then increment the value at index and set all the values from 0 to index - 1 to zero
Repeat the last step until the vector is valid
For example, (next-hand [0 0 0 0 1 1 1]) would return [0 0 0 1 1 1 1] directly. However, (next-hand [0 0 0 1 1 1 1]) would loop through,
[0 0 1 1 1 1 1] (invalid)
[0 1 1 1 1 1 1] (invalid)
[1 1 1 1 1 1 1] (invalid)
[0 0 0 0 0 0 2] (invalid)
[0 0 0 0 0 1 2] (invalid)
and return this valid hand:
[0 0 0 0 1 1 2]
Here is the sudo code I have, but need to convert this to clojure. Note how I'm adding a really large integer to the end of the hand to make the last comparison always true. Thus, in the case of [1 1 1 1 1 1 1 99] the first loop would end at i=6 with 1 < 99 == true.
let hand = [hand 99]
while hand is invalid
for i in range(0,6)
if hand[i] < hand[i+1]
increment hand[i]
break
for j in range(0,i-1)
hand[j] = 0
Edit Friday, Mar 29, 2013:
In order for the select solution to work with the poker hand model I added an is-valid function like so:
(defn is-valid [v]
(let [distinct-ranks (partition-by identity v)
count-distinct (map count distinct-ranks)
max-count (apply max count-distinct)]
(<= max-count 4)))
and updated to (filter #(is-valid %) in next-hand.
One possible solution:
(defn next [v]
(let [i (->> (map < v (rest v))
(map-indexed vector)
(filter #(% 1))
first)
index (if i (i 0) 6)]
(for [[i x] (map-indexed vector v)]
(cond (= i index) (inc x)
(< i index) 0
:else x))))
(defn next-hand [v]
(->> (iterate next (next v))
(filter #(= 4 (apply + %)))
first
vec))
(next-hand [0 0 0 1 1 1 1])

count unique values in vector in clojure

I was wondering if anyone can help me understand how can i do the below code in clojure :
int[] secondArray = new int[500];
for (int i = 0; i < firstArray.length; i++)
{
secondArray[firstArray[i]] += 1;
}
You could probably use the frequencies function:
user=> (frequencies [:foo :bar :baz :foo :foo])
{:foo 3, :bar 1, :baz 1}
Let's walk through a fairly direct translation where we treat the input vector as a sequence and then reduce it into the desired result:
First define some immutable vectors containing our starting states:
boo> (def firstVector (vec (take 30 (repeatedly #(rand-int 10)))))
#'boo/firstVector
boo> firstVector
[9 0 4 5 0 7 3 9 0 0 6 6 5 5 9 4 0 1 3 6 4 9 5 8 8 3 4 6 7 6]
boo> (def secondVector (vec (take 10 (repeat 0))))
#'boo/secondVector
boo> secondVector
[0 0 0 0 0 0 0 0 0 0]
We then want an expression that incs the appropriate element in the second array
boo> (assoc secondVector 4 (inc (secondVector 4)))
[0 0 0 0 1 0 0 0 0 0]
Then we want the result of that to be passed to the frist element in firstVector, followed by the result of that being passed to the second element in firstVector and so forth. The reduce function does this:
boo> (reduce #(assoc %1 %2 (inc (%1 %2))) secondVector firstVector)
[5 1 0 3 4 4 5 2 2 4]
in the reducer function %1 (the first argument) is the current accumulated result, and %2(the second argument) is the current value from the input sequence (firstVector).