Unflattening a sequence to sequences of repeating elements (clojure) - 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!

Related

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])

Map with repeated argument clojure

Consider the following function as an example:
(defn f [x y] (+ x y))
I want to use this function to add 2 to each element of a vector:
[1 2 6 3 6]
I can use map:
(map f [1 2 6 3 6] [2 2 2 2 2])
But it seems a little ugly creating the second vector where every element is exactly the same.
So I thought using a closure was a better approach:
(map (fn g [x] (f x 2)) [1 2 6 3 6])
So my question is:
In clojure, what is the best way to use map when some arguments are not changing?
Just apply partial function
(map (partial + 2) [1 2 6 3 6]) => (3 4 8 5 8)
Approach 1: use repeat.
(repeat 2) gives you a lazy sequence of infinite 2s
In your case,
(map f [1 2 6 3 6] [2 2 2 2 2])
should be converted into
(map f [1 2 6 3 6] (repeat 2))
Approach 2: use anonymous function
(map #(f % 2) [1 2 6 3 6])

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]))

How to split a sequence into every 3 neighbor elements in clojure?

Given a sequence like:
[1 2 3 4 5 6]
How to split it into every 3 neighbor elements in clojure? Just like the following:
([1 2 3] [2 3 4] [3 4 5] [4 5 6])
Functions in clojure.core are preferred!
See partition:
user=> (partition 3 1 [1 2 3 4 5 6])
((1 2 3) (2 3 4) (3 4 5) (4 5 6))