What I am ultimately trying to do is multiply two vectors together and return a vector of the same size eg:
[6 7 8 9 10] * [0 1 3 1 0] => [0 7 24 9 0]
I was attempting to do something like:
(partition 2 (interleave [6 7 8 9 10] [0 1 3 1 0])) => ((6 0) (7 1) (8 3) (9 1) (10 0))
... then multiply each nested list value and use flatten to get:
(0 7 24 9 0)
but I cant figure out how I could multiply nested list values?
Map takes multiple sequences and a function to combine each member with the corresponding member of the other sequences.
user> (map * [6 7 8 9 10] [0 1 3 1 0])
(0 7 24 9 0)
user> (mapv * [6 7 8 9 10] [0 1 3 1 0])
[0 7 24 9 0]
in this case it calls * on the first number from each list, then on the second from each list and so on, building a seq of the output. If you would prefer the output in a vector mapv is convenient.
Related
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))))
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)
I understand how map works but I am confused by this example:
(def check-sum
(fn [sequence]
(apply + (map *
(range 1 (inc (count sequence)))
sequence))))
The map part looks like this when given a sequence:
(map * (range 1 (inc (count [5 1 1 4 7 7 1 3 1 0]))) [5 1 1 4 7 7 1 3 1 0])
Which returns this:
(5 2 3 16 35 42 7 24 9 0)
I do not understand where the current item in the map is being multiplied. I would understand if it was using an anonymous function of the form #(* %) etc.
But there is no anonymous function in this example.
The first argument of map should be function and the number of parameter should be matched to the number of collections provided. So, if you want to pass an anonymous function, you should write the code like this:
(map #(* %1 %2) [1 3 5] [2 4 6])
;=> (2 12 30)
(map #(* %1 %2 %3) [1 3 5] [2 4 6] [3 5 7])
;=> (6 60 210)
But * itself is a function which can take any number of arguments (check (doc *) from REPL), you can write the code in a simpler form:
(map * [1 3 5] [2 4 6])
;=> (2 12 30)
(map * [1 3 5] [2 4 6] [3 5 7])
;=> (6 60 210)
* is applied to the set of first elements of each collection, set of second elements, ...
Other functions like +, -, / can be used in this way, too.
No anonymous function is needed, because the named function * is what's doing the multiplying. Two collections are passed to map, so it passes the corresponding elements from each collection to the * function.
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))
If I have a Vector:
[1 2 3 4 5 6 7 8 9]
: and I want to replace the 5 with a 0 to give:
[1 2 3 4 0 6 7 8 9]
How can I do this when I only know the index as being 4?
Something like:
(replace-in-vec [1 2 3 4 5 6 7 8 9] 4 0)
assoc works with vectors too!
Usage: (assoc map key val)
(assoc map key val & kvs)
assoc[iate]. When applied to a map,
returns a new map of the same
(hashed/sorted) type, that contains
the mapping of key(s) to val(s). When
applied to a vector, returns a new
vector that contains val at index.
Note - index must be <= (count
vector).
(assoc [1 2 3] 1 :a)
=> [1 :a 3]
You want assoc: http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/assoc