I have a vector that contains numbers.
The structure of the vector is the following:
items of arbitrary length
a separator [0 0 0 0 0] (0 repeated 5 times) between the items
I want to write a function split that retrieves the list of the items (without the separator): It is similar to string/split.
For instance:
(split [123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 199])
; => [[123 0 1] [1 1] [1 0 1] [0 0 1 199]]
Remark: the code has to be effective as the length of the vector is around 1 million.
Thanks for your help.
Here:
(defn the-split [coll]
(let [part (partition-by identity coll)
ppart (partition-by #(= [0 0 0 0 0] %) part)
almost (map #(apply concat %) ppart)]
(filter (partial not= [0 0 0 0 0]) almost)))
(the-split [123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 199])
=> ((123 0 1) (1 1) (1 0 1) (1 199))
Here's one approach -- with the [0 0 0 0 0] separator hardwired, but straightforward to generalize:
(defn split5z [xs]
(let [delim [0 0 0 0 0]
step (fn step [xs seg]
(lazy-seq
(if-let [xs (seq xs)]
(let [window (take 5 xs)]
(if (= window delim)
(cons seg (step (drop 5 xs) []))
(step (rest xs) (conj seg (first xs)))))
(list seg))))]
(step xs [])))
Applying it to your sample input:
(split5z [123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 199])
;= ([123 0 1] [1 1] [1 0 1] [1 199])
Wrap in vec if you'd like the output to be a vector rather than a seq of vectors.
Another approach -- this time eagerly consuming the input with loop/recur:
(defn split5z [sep xs]
(let [scnt (count sep)]
(loop [xs (seq xs)
out []
seg []]
(if xs
(if (= (take scnt xs) sep)
(recur (nthnext xs scnt)
(conj out seg)
[])
(recur (next xs)
out
(conj seg (first xs))))
(if (seq seg)
(conj out seg)
seg)))))
At the REPL:
(split5z [0 0 0 0 0]
[123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 199])
;= [[123 0 1] [1 1] [1 0 1] [1 199]]
A lazy solution:
(defn split [v]
(let [delim (repeat 5 0)
i (->> v (partition 5 1) (take-while #(not= delim %)) count)]
(if (zero? i) [v] (lazy-seq (cons (subvec v 0 i)
(split (subvec v (+ i 5))))))))
For example
(split [123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 199])
; ([123 0 1] [1 1] [1 0 1] [0 0 1 199])
Related
I have an atom which stores current and historical event counts.
(def buckets (atom (list)))
It starts as 20 empty values.
(reset! buckets (apply list (repeat 20 0)))
=> (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
The head bucket gets incremented for each event.
(defn- inc-bucket [buckets]
(conj (rest buckets) (inc (first buckets))))
(defn event-happened [] (swap! buckets inc-bucket))
=> (event-happened)
(1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
It gets shifted once a second to give a history of counts.
(defn- shift-buckets [buckets]
(conj (drop-last buckets) 0))
(once-a-second-run (swap! buckets shift-bucket))
=> (swap! buckets shift-bucket)
(0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
This all works fine most of the time. But occasionally (say once a week) I find that the length of buckets has been reset to 5, not the correct value (20 in this example).
=> #buckets
(0 1 0 0 0)
The only place buckets is used is in these functions and with a deref to observe the value.
Something went wrong, and I can't work out how or where. The only place buckets is modified is during the two above swap!s and as I think they're being used correctly. Any ideas?
I found the answer. Laziness and unhandled exceptions in atoms. There is no magic.
user=> (reset! buckets (apply list (repeat 20 0)))
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
user=> (dotimes [_ 99999] (swap! buckets shift-buckets))
nil
user=> #buckets
StackOverflowError clojure.core/map/fn--4557 (core.clj:2627)
user=> (type #buckets)
clojure.lang.Cons
This had showed up in the log, but I hadn't seen it (there's a lot else going on). But here's the crazy thing:
user=> #buckets ; again
(0 0)
I don't know why it would give that value. It's not because a cons cell has a head and a tail, because in production that was (0 0 0 0 0). Either way it's undefined behaviour so there's no point guessing.
To fix it, the list must be realised each time.
user=> (defn- shift-buckets-nonlazy [buckets]
#_=> (apply list (conj (drop-last buckets) 0)))
#'user/shift-buckets-nonlazy
user=> (reset! buckets (apply list (repeat 20 0)))
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
user=> (dotimes [_ 999999] (swap! buckets shift-buckets-nonlazy))
nil
user=> (type #buckets)
clojure.lang.PersistentList
user=> #buckets
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
The problem has to be in code you haven't posted: everything in your question looks perfectly correct, and can't cause the behavior you describe.
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])
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).
Given a vector of ones and zeros, I would like to count the number of entries with a value one. However, the vector may be very long and I only care to know if the vector has zero, one, or more entries with a value o f one.
Using the approach given here, I can count the number of ones in the vector.
(count (filter #{1} [1 0 1 0 0 1 1]))
Can I limit filter (or use some other approach) to avoid visiting any more than three elements of the vector, in this case?
Filter is lazy, so will only do as much work as required. Since you only care about having no 1's, one 1's or two or more ones, you only need to examine up to two elements of the filtered sequence of 1's, so just take 2 before you count:
user=> (count (take 2 (filter #{1} [1 0 1 0 0 1 1])))
2
user=> (count (take 2 (filter #{1} [0 0 0 0 0 0 0])))
0
user=> (count (take 2 (filter #{1} [0 0 0 0 0 0 1])))
1
user=> (def rare (repeatedly #(if (< (rand) 0.0001) 1 0)))
#'user/rare
user=> (take 10 rare)
(0 0 0 0 0 0 0 0 0 0)
user=> (count (take 2 (filter #{1} rare)))
2
I'm quite new to clojure so still trying to learn... well a LOT of stuff. Right now I'm stuck on trying to get some output to display properly. Here is my function:
;function 7 - display the board
(defn display [small medium large]
(let [board (loop [i 0 boardVector [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]
;(prn (bit-test small i)(bit-test medium i)(bit-test large i))
(if (< i 16)
(cond
;nothing exists
(and (not(bit-test small i))(not(bit-test medium i))(not(bit-test large i)))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 0)))
;only small bit exists
(and (bit-test small i)(not(bit-test medium i))(not(bit-test large i)))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 1)))
;small and medium exists on square
(and (bit-test small i)(bit-test medium i)(not(bit-test large i)))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 3)))
;only medium exists on square
(and (not(bit-test small i))(bit-test medium i)(not(bit-test large i)))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 2)))
;medium and large exists on square
(and (not(bit-test small i))(bit-test medium i)(bit-test large i))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 6)))
;only large exists on square
(and (not(bit-test small i))(not(bit-test medium i))(bit-test large i))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 4)))
;all three exists on square
(and (bit-test small i)(bit-test medium i)(bit-test large i))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 7)))
)
boardVector)
)
]
(prn board)
)
)
Here is what I'm using to pass as arguments:
(display 2r1001000100 2r101001000 2r111000000)
This function takes bit variables (that are no more than 16 in length...), and calculates a final vector depending on which bits are set. a small is worth 1, medium worth 2, large worth 4. This is why I have that condition statement outlining each different possibility, excluding the possibility of having a small and large, and no medium set at the same time.
Anyhow, if none of that makes sense, here's the actual question:
How do I get my current output that displays as:
[0 0 1 2 0 0 7 4 6 1 0 0 0 0 0 0]
nil
To make it display like this?
0 0 1 2
0 0 7 4
6 1 0 0
0 0 0 0
I've tried using functions such as apply, map, str, interpose... but I never could figure out what the heck I was doing wrong with them. Currently I have the output displayed as a side-effect (i think that is the correct name for that...), but it's always returning nil from the output of the prn function. Dunno how to get rid of that either. Would appreciate any help!
partition it into groups of 4, then print each group:
(dorun (map #(apply println %) (partition-all 4 r)))
0 0 1 2
0 0 7 4
6 1 0 0
0 0 0 0
or using a for expression:
(dorun (for [line (partition-all 4 r)] (apply println line)))
0 0 1 2
0 0 7 4
6 1 0 0
0 0 0 0
or using a doseq:
(doseq [line (partition-all 4 r)] (apply println line))
0 0 1 2
0 0 7 4
6 1 0 0
0 0 0 0
dorun (or doall) is required for the for and map examples because these are lazy and would otherwise not actually print anything unless the sequence they return was consumed. Calling apply with println and the sequence causes println to get the contents of the sequence as arguments instead of the sequence it's self, which keeps it from printing extra parens.