How to convert a map into a collection without the keys - clojure

I have a map like this:
{1 [1 4 7], 2 [2 5 8], 0 [3 6 9]}
I want to write a function that returns this:
[[1 4 7] [2 5 8] [3 6 9]]
As a side note, I'm getting the map by doing this:
(group-by #(mod % 3) [1 2 3 4 5 6 7 8 9])
If anyone has a shortcut for going from a vector like this: [1 2 3 4 5 6 7 8 9] to the second one shown above, please let me know!

As to your other question: (partition 3 v) creates a matrix, and (apply map vector m) is an idiom to transpose a matrix m (how does it work? Exercise for the reader or google it). So:
> (apply map vector (partition 3 [1 2 3 4 5 6 7 8 9]))
([1 4 7] [2 5 8] [3 6 9])
There are other ways of course. For example, with destructuring:
> (let [{ a 0 b 1 c 2 } (group-by #(mod % 3) [1 2 3 4 5 6 7 8 9])] [b c a])
[[1 4 7] [2 5 8] [3 6 9]]

Does order matter? vals is takes a map, and returns a sequence of the values. But order is not defined for a map, so the order of the values sequence returned is arbitrary.
> (vals {1 [1 4 7], 2 [2 5 8], 0 [3 6 9]})
([3 6 9] [1 4 7] [2 5 8])
Sorted:
> (sort (vals {1 [1 4 7], 2 [2 5 8], 0 [3 6 9]}))
([1 4 7] [2 5 8] [3 6 9])

Related

How do I check if any element of a vector is in the value of a hashmap?

I have vectors with a list of tiles and a map of adjacent tiles (like a graph). I want to return true if there are any adjacent tiles and false if there are no adjacent tiles. So comparing [1 3 19] should be true, because (adjacents 1) contains 3. While comparing [1 14 19] should be false because (adjacents 1) does not contain 14 or 19, (adjacents 14) does not contain 1 or 19 and (adjacents 19) does not contain 1 or 14.
So tile 1 is adjacent to tiles 2, 3, 4, 5, 6 and 7.
(def adjacents
{1 [2 3 4 5 6 7]
2 [1 3 7 8 9 10]
3 [1 2 4 10 11 12]
4 [1 3 5 12 13 14]
5 [1 4 6 14 15 16]
6 [1 5 7 16 17 18]
7 [1 2 6 8 18 19]
8 [2 7 8 18]
9 [2 8 10]
10 [2 3 9 11]
11 [3 10 12]
12 [3 4 11 13]
13 [4 12 14]
14 [4 5 13 15]
15 [5 14 16]
16 [5 6 15 17]
17 [6 16 18]
18 [6 7 17 19]
19 [7 8 18]})
I've thought about using map, but I can't figure out what function to put inside it. Also thought about turning the values of the hashmap into a set and the vector into a set then comparing the intersection but I'm not thinking about this correctly.
You can write a function that loops over the possible pairs of adjacent vertices and checks if any of the pairs are adjacent:
(defn any-adjacent? [adjmap vertices]
(seq (for [a vertices
b vertices
x (adjmap a)
:when (= x b)]
a)))
(any-adjacent? adjacents [1 3 19])
;; => (1 3)
(any-adjacent? adjacents [1 14 19])
;; => nil
If you use sets instead of vectors as suggested by #amalloy, that is
(def adjacents {1 #{7 4 6 3 2 5},
2 #{7 1 3 9 10 8}
...
})
it is possible to implement more concisely and with better time complexity:
(defn any-adjacent? [adjmap vertices]
(seq (for [a vertices
b vertices
:when ((adjmap a) b)]
a)))
You could collect all the adjacent tiles with mapcat, then test whether that collection contains any of your tiles using some:
(defn any-adjacent [graph tiles]
(some (set tiles)
(mapcat graph tiles)))
(any-adjacent adjacents [1 3 19])
; => 3
(any-adjacent adjacents [1 14 19])
; => nil
(any-adjacent adjacents [8])
; => 8
If the return value needs to be Boolean:
(defn any-adjacent? [graph tiles]
(some? (some (set tiles)
(mapcat graph tiles))))
The main part of the solution will be function some.
For each number in the given vector v, you have to find a vector of adjacent elements: (graph %) and then compare this vector to other elements in v, using second some: (some (disj (set v) %) (graph %)). So, I think this should work:
(defn any-adjacent? [graph v]
(some #(some (disj (set v) %)
(graph %))
v))
Tests:
(def adjacents
{1 [2 3 4 5 6 7]
2 [1 3 7 8 9 10]
3 [1 2 4 10 11 12]
4 [1 3 5 12 13 14]
5 [1 4 6 14 15 16]
6 [1 5 7 16 17 18]
7 [1 2 6 8 18 19]
8 [2 7 8 18]
9 [2 8 10]
10 [2 3 9 11]
11 [3 10 12]
12 [3 4 11 13]
13 [4 12 14]
14 [4 5 13 15]
15 [5 14 16]
16 [5 6 15 17]
17 [6 16 18]
18 [6 7 17 19]
19 [7 8 18]})
(any-adjacent? adjacents [1 3 19])
=> 3
(any-adjacent? adjacents [1 14 19])
=> nil
This is the solution I came up with. It turns the list of locations and the values of the map into sets then takes the intersection. If the intersection is empty, there is no overlap so nothing is adjacent. By using map on the hashmap, it pulls all the relevant values out.
(defn adjacent?
[locations-v neighbors-m]
(let [loc-set (set locations-v)
neighbors-set (set (flatten (map neighbors-m locations-v)))]
(seq (set/intersection loc-set neighbors-set))))

Clojure: 'folding' a sequence (partitioning, as it turned out)

What is the right way of turning a flat list like this:
(1 2 3 4 5 6 7 8 9)
into a sequence of vectors:
([1 2 3] [4 5 6] [7 8 9])
Sorry, I suppose this is something right out of the toolbox, but I can't think of the right keyword.
(->> '(1 2 3 4 5 6 7 8 9) (partition 3) (map vec))
Take the original list and then partition it by 3 and finally map each partition to a vector.
I think using the ->> macro makes it read nicer.
user> (def flat-seq (range 1 10))
#'user/flat-seq
user> (map vec (partition-all 3 flat-seq))
;=> ([1 2 3] [4 5 6] [7 8 9])

Reshaping nested vectors

Given a nested vector A, which is the 3 x 4 matrix
[[1 4 7 10] [2 5 8 11] [3 6 9 12]]
Transform A such that the nested vector (matrix) is now 2 x 6.
The output would look like
[[1 3 5 7 9 11] [2 4 6 8 10 12]]
As of now I am stuck on the beginning implementation of this idea.
You might want to look into core.matrix:
;; using [net.mikera/core.matrix "0.18.0"] as a dependency
(require '[clojure.core.matrix :as matrix])
(-> [[1 4 7 10] [2 5 8 11] [3 6 9 12]]
(matrix/transpose)
(matrix/reshape [6 2])
(matrix/transpose))
;= [[1 3 5 7 9 11] [2 4 6 8 10 12]]
this function will reshape m to be composed of subvectors with the desired shape
(defn reshape [m & shape]
(reduce (fn [vecs dim]
(reduce #(conj %1 (subvec vecs %2 (+ dim %2)))
[] (range 0 (count vecs) dim)))
(vec (flatten m)) (reverse shape)))
example:
(reshape [1 [2 3 4] 5 6 7 8] 2 2) => [[[1 2] [3 4]] [[5 6] [7 8]]]

What is the closest match to this Clojure map/apply expression, in Rebol?

While comparing functional expressions in Clojure side-by-side with Rebol, I happened onto this expression from the examples of apply used in combination with map, at clojure-docs.org:
user=> (map #(apply max %) [[1 2 3] [4 5 6] [7 8 9]])
(3 6 9)
What is the most similar expression Rebol?
Perhaps:
map-each x [[1 2 3] [4 6 5] [7 8 9]] [apply :reduce [first maximum-of x]]
But you don't need to use apply here:
map-each x [[1 2 3] [4 6 5] [7 8 9]] [first maximum-of x]
NB. Notice that I changed middle list to [4 6 5]. This is important because...
maximum-of [4 6 5] ; => [6 5]
Which isn't the same as max in Clojure (which returns highest number found in list).
A similar expression in Rebol would be:
>> map-each x [[1 2 3] [4 5 6] [7 8 9]] [apply :reduce maximum-of x]
== [3 6 9]
map-each x [[1 2 3] [4 5 6] [7 8 9]] [first maximum-of x]

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