How to swap 2 elements in Vector of Vector - clojure

How do I extend this:
What is the idiomatic way to swap two elements in a vector
to essentially a 2D array?
[[1 2 3] [4 5 6] [7 8 9]] --> [[1 2 5] [4 3 6] [7 8 9]]

Use get-in and assoc-in:
(defn swap-in [vv p1 p2]
(let [v1 (get-in vv p1)
v2 (get-in vv p2)
(-> vv
(assoc-in p1 v2)
(assoc-in p2 v1))))
So now:
(def my-vec [[1 2 3] [4 5 6] [7 8 9]])
(swap-in my-vec [0 2] [1 1])
=> [[1 2 5] [4 3 6] [7 8 9]]
This will work with vectors nested to any "depth", so long as the specified positions in my-vec actually exist.

Related

Clojure - Applying a Function to a vector of vectors

I have a vector [[[1 2] [3 4]] [[5 6] [7 8]] [9 10] 11]. I want to apply a function to this vector but keep the data structure.
For example I want to add 1 to every number but keep the data structure to get the result being [[[2 3] [4 5]] [[6 7] [8 9]] [10 11] 12]. Is this possible?
I have tried
(map #(+ 1 %) (flatten [[[1 2] [3 4]] [[5 6] [7 8]] [9 10] 11]))
=> (2 3 4 5 6 7 8 9 10 11 12)
But you can see that the data structure is not the same.
Is there maybe a function that takes (2 3 4 5 6 7 8 9 10 11 12) to [[[2 3] [4 5]] [[6 7] [8 9]] [10 11] 12]
I thought maybe to use postwalk but I'm not sure if this is correct.
Any help would be much appreciated
You can use postwalk:
(require '[clojure.walk :as walk])
(let [t [[[1 2] [3 4]] [[5 6] [7 8]] [9 10] 11]]
(walk/postwalk (fn [x] (if (number? x) (inc x) x)) t))
also the classic recursive solution is not much more difficult:
(defn inc-rec [data]
(mapv #((if (vector? %) inc-rec inc) %) data))
#'user/inc-rec
user> (inc-rec [1 [2 3 [4 5] [6 7]] [[8 9] 10]])
;;=> [2 [3 4 [5 6] [7 8]] [[9 10] 11]]
Another way to solve your problem is via Specter. You do need another dependency then, but it can be a helpful library.
(ns your-ns.core
(:require [com.rpl.specter :as specter]))
(def data [[[1 2] [3 4]] [[5 6] [7 8]] [9 10] 11])
(specter/defprotocolpath TreeWalker) ;; define path walker
(specter/extend-protocolpath TreeWalker
;; stop walking on leafs (in this case long)
Object nil
;; when we are dealing with a vector, TreeWalk all elements
clojure.lang.PersistentVector [specter/ALL TreeWalker])
You can extend it to perform more complicated operations. For this use case normal Clojure is good enough.
(specter/transform [TreeWalker] inc data)
;; => [[[2 3] [4 5]] [[6 7] [8 9]] [10 11] 12]

Clojure - Combining Two vectors into a vector of vectors [duplicate]

This question already has answers here:
Clojure - Splitting a vector
(3 answers)
Closed 5 years ago.
How can I combine [[1 2] [3 4]] and [5 6] to get [[1 5] [2 5] [3 6] [4 6]]
I tried (map vector [[1 2] [3 4]] [5 6]) but the result was ([[1 2] 5] [[3 4] 6])
Any help would be much appreciated. Thanks
You can use mapcat and an inner map like this:
user=> (mapcat (fn [as b]
(mapv #(vector % b) as))
[[1 2] [3 4]] [5 6])
([1 5] [2 5] [3 6] [4 6])

Clojure - Splitting a vector

If I have two arguments [[1 2] [3 4]] and [5 6], how can I get to [[1 5] [2 6] [3 5] [4 6]].
I thought I may have to use for so I tried,
(for [x [[1 2] [3 4]]]
(for [xx x]
(for [y [5 6]] [xx y])))
But it returned ((([1 5] [1 6]) ([2 5] [2 6])) (([3 5] [3 6]) ([4 5] [4 6])))
Any help would be much appreciated. Thanks
(mapcat #(map vector % [5 6]) [[1 2] [3 4]])
or using for:
(for [c [[1 2] [3 4]]
p (map vector c [5 6])]
p)
If I understood your question correctly, your solution is actually very close. You did not need to nest the for expressions explicitly, since doing so creates a new list at every level, instead, just use multiple bindings:
(for [x [[1 2][3 4]]
xx x
y [5 6]]
[xx y])
Which will result in
([1 5] [1 6] [2 5] [2 6] [3 5] [3 6] [4 5] [4 6])
Edit
Now that I finally read your question carefully, I came up with the same answer as #Lee did (mapcat (fn[x] (map vector x [5 6])) [[1 2] [3 4]]), which is the right one and should probably be accepted.
This is one (hmm - not particularly elegant) way to get your answer, without using for:
(defn f [x y]
(let [x' (apply concat x)
multiples (/ (count x') (count y))
y' (apply concat (repeat multiples y))]
(mapv vector x' y')))
(f [[1 2] [3 4]] [5 6])
;;=> [[1 5] [2 6] [3 5] [4 6]]

How do I pass var args to an anonymous function in Clojure?

Is it possible to do var args for an anonymous function in Clojure?
For example, how do I turn:
(#(reduce + (map * %1 %2 %3)) [1 2 3] [4 5 6] [7 8 9])
into something like,
(#(reduce + (map * [& args])) [1 2 3] [4 5 6] [7 8 9])
This solves the problem:
user> ((fn[& args] (reduce + (apply map * args))) [1 2 3] [4 5 6] [7 8 9])
270
or
user> (#(reduce + (apply map * %&)) [1 2 3] [4 5 6] [7 8 9])
270
Use the apply function
I'm not aware of a way to do this with the #(...) syntax, but here is your example using fn
((fn [& args] (reduce + (apply map * args))) [1 2 3] [4 5 6] [7 8 9])
You can use %& to get the rest argument in the #(...) form, resulting in
(#(reduce + (apply map * %&)) [1 2 3] [4 5 6] [7 8 9])

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]