关于Clojure:Clojure-将函数应用于向量vector

Clojure - Applying a Function to a vector of vectors

我有一个向量[[[1 2] [3 4]] [[5 6] [7 8]] [9 10] 11]。我想对该向量应用一个函数,但保留数据结构。

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

我尝试了

1
2
(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

1
2
3
4
(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))


经典的递归解决方案也并不困难:

1
2
3
4
5
6
(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]]

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

1
2
3
4
5
6
7
8
9
10
11
(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就足够了。

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