Reputation: 999
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
Upvotes: 5
Views: 444
Reputation: 10474
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]
Upvotes: 0
Reputation: 17859
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]]
Upvotes: 4
Reputation: 144116
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))
Upvotes: 6