how to remove a particular occurances from sequence clojure - 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])

Related

Clojure: Same vector values in a row checker

I'm creating an Clojure Tic Tac Toe game, where I have a board variable with 9 numbers (def moves [0 0 0 0 0 0 0 0 0]) . This variable gets filled with 1's en 2's (no "x" or "o" yet). At the end of the game the variable could look like [2 1 2 1 1 1 2 1 2] where 1 owns the second row. Now I need a function to check if there's three in a row. I wanted to start horizontally. Which means I need a function to check if there's after each 3 numbers 3 of the same number are in a row. any ideas how I can create a function like this?
So this is the function so far:
(def moves [0 0 0 0 0 0 0 0 0])
(defn wongame? [playedmoved]
(
(def counter 0)
;action here....
)
)
(won moves) ;gives true/false
Something like this should work:
(defn end-of-game? [moves]
(->> moves
(partition 3)
(remove #(= [0 0 0] %))
(map (partial apply =))
(some identity)))
With your example input of [2 1 2 1 1 1 2 1 2] (partition 3) gives:
((2 1 2) (1 1 1) (2 1 2))
We need to use = with each list. apply is required because = works with individual arguments rather than a list. partial is required because the parameters to apply = are pending. #(apply = %) could have equivalently been used.
(false true false)
some is all about '(at least) one or none'. Here if one of the list it is passed is truthy then that one will be returned.
If you really need the answer to return true/false then put a call to boolean as the last function to the thread last macro (->>). I've left that out because only rarely do you need to actually return true or false in Clojure - you can rely on nil punning.
This same function will work for vertically as well. Start off with a general transpose function that works for a matrix (e.g. [[0 0 0][0 0 0][0 0 0]]):
(defn transpose [matrix]
(apply mapv vector matrix))
Then fashion your input before, and its output after:
(defn transpose-flat [xs]
(->> xs
(partition 3)
transpose
(mapcat identity)))
(def moves [0 0 1 1 0 1 2 2 2]) #_"the game's state in the middle"
At first, if we encounter like this pattern, we need stop the game,
Otherwise we are possible to misjudge the winner of this game
if the moves reaches the state like [2 2 1 1 1 1 2 2 2]. Which is the winner? We need to call this function each turn of the game.
Second, the name "won?" isn't appropriate because this function doesn't tell the winner, but tells the end of game. "won?" function should be renamed like ["end-of-game?" "game-end?" "end?"].
Third, I try to implement "winner" that returns the winner of the game like this:
(defn winner [moves]
(let [pattern-of-end {[1 1 1]:1 [2 2 2]:2}]
(->> moves #_"I use threading macro to explain"
(partition 3) #_"group by each three symbols.
1 line of 9 elements -> 3 lines of 3 elements"
(keep pattern-of-end) #_"If there is some lines that matches
the pattern-of-end ,that will return [1] or [2]"
first #_"Because the previous expression returns lazy-seq
we can get the scalar by calling first"
)))
This tells us the winner of the game.
It would have been easier if you had proper numbers for x's and o's:
(defn the-winner-is [moves]
(let [x 5
o 7]
(->> moves
(partition 3)
(map (partial apply +))
(some #{15 21}))))
This way it even says who is the winner (15 or 21).
(the-winner-is [5 5 7 7 7 0 7 7 7]) ; 21
(the-winner-is [5 5 5 7 7 5 5 7 7]) ; 15
(the-winner-is [5 7 5 7 7 5 5 7 5]) ; nil

Digits back to number again

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.

Clojure, concat multiple sequences into one

The following line: (repeat 4 [2 3])
gives me this: ([2 3] [2 3] [2 3] [2 3])
How do I create one vector or list from the above list of vectors so that I get this?: [2 3 2 3 2 3 2 3]
Thanks
concat is in fact exactly the function you want
user> (apply concat (repeat 4 [2 3]))
(2 3 2 3 2 3 2 3)
this even works with lazy input:
user> (take 8 (apply concat (repeat [2 3])))
(2 3 2 3 2 3 2 3)
This is an alternative:
user> (def flatten-1 (partial mapcat identity))
#'user/flatten-1
user> (flatten-1 (repeat 4 [2 3]))
(2 3 2 3 2 3 2 3)
it is compatible with laziness and unlike flatten preserves any substructure (only doing one level of flattening)
user> (take 12 (flatten-1 (repeat [2 3 [4]])))
(2 3 [4] 2 3 [4] 2 3 [4] 2 3 [4])
(take 8 (cycle [2 3]))
;; => (2 3 2 3 2 3 2 3)
(flatten x)
Takes any nested combination of sequential things (lists,
vectors, etc.) and returns their contents as a single, flat sequence.
(flatten nil) returns nil.
(flatten (repeat 4 [2 3])) ;(2 3 2 3 2 3 2 3)
Pedantically speaking, you asked for a vector, so:
(->> [2 3] cycle (take 8) vec)
I feel cycle is a little more appropriate than concat (though it uses concat itself) as it indicates "cycle through the elements of this sequence" rather than "concatenate the following sequences together". Just my two cents, matter of opinion.

finding if a vector's all elements only appear once

I have a vector - [1 2 3 4]
I want to check that in the vector each element appears only once. How do I do it ? One way I can think of is to convert it into a set and then back into the vector and then compare both :) However I think there should be a simpler way ...
You can use distinct?:
(apply distinct? [1 2 3 4]) ;=> true
(apply distinct? [1 2 3 4 4]) ;=> false
You can use distinct:
(distinct [1 2 3 4 5 5]) -> [1 2 3 4 5]
For a check, you can do something like:
(= [1 2 3 4 5 5] (distinct [1 2 3 4 5 5]))

Unflattening a sequence to sequences of repeating elements (clojure)

In Clojure, how do you partition a sequence to subsequences of repeating elements? E.g. :
[1 2 2 3 3 3 4 2 2 1 1 1]
to
[[1] [2 2] [3 3 3] [4] [2 2] [1 1 1]]
I've been playing around with some examples trying to understand clojure better, and was stuck on this one for some time.
user> (partition-by identity [1 2 2 3 3 3 4 2 2 1 1 1])
((1) (2 2) (3 3 3) (4) (2 2) (1 1 1))
user> (vec (map vec (partition-by identity [1 2 2 3 3 3 4 2 2 1 1 1])))
[[1] [2 2] [3 3 3] [4] [2 2] [1 1 1]]
(map (juxt count first)
(partition-by identity [1 1 1 3 2 2]))
((3 1) (1 3) (2 2))
Three ones, then one three, followed by two twos!