2017-07-14 16 views
5

我有一个矢量[[[1 2] [3 4]] [[5 6] [7 8]] [9 10] 11]。我想对这个向量应用一个函数,但保留数据结构。Clojure - 将函数应用于矢量载体

例如,我想为每个数字加1,但保留数据结构以得到结果为[[[2 3] [4 5]] [[6 7] [8 9]] [10 11] 12]。这可能吗?

我已经试过

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

但是你可以看到,数据结构是不一样的。

是否有可能一个函数,(2 3 4 5 6 7 8 9 10 11 12)[[[2 3] [4 5]] [[6 7] [8 9]] [10 11] 12]

我想,也许使用postwalk,但我不知道这是正确的。

任何帮助,将不胜感激

回答

6

您可以使用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)) 
4

也是经典的递归解决方案是不是要困难得多:

(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]] 
0

另一种方法来解决你的问题通过Specter。您确实需要另一个依赖项,但它可能是一个有用的库。

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

您可以扩展它来执行更复杂的操作。对于这个用例,正常的Clojure已经足够好了。

(specter/transform [TreeWalker] inc data) 
;; => [[[2 3] [4 5]] [[6 7] [8 9]] [10 11] 12]