2017-07-14 21 views
5

Tôi có một vector [[[1 2] [3 4]] [[5 6] [7 8]] [9 10] 11]. Tôi muốn áp dụng một chức năng cho vector này nhưng giữ cấu trúc dữ liệu.Clojure - Áp dụng một chức năng cho vec tơ vectơ

Ví dụ: tôi muốn thêm 1 vào mọi số nhưng giữ cấu trúc dữ liệu để có được kết quả là [[[2 3] [4 5]] [[6 7] [8 9]] [10 11] 12]. Điều này có thể không?

Tôi đã thử

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

Nhưng bạn có thể thấy rằng các cấu trúc dữ liệu là không giống nhau.

Có lẽ một hàm mang theo (2 3 4 5 6 7 8 9 10 11 12)-[[[2 3] [4 5]] [[6 7] [8 9]] [10 11] 12]

Tôi nghĩ có lẽ sử dụng postwalk nhưng tôi không chắc chắn nếu điều này là đúng.

Bất kỳ trợ giúp sẽ được nhiều đánh giá cao

Trả lời

6

Bạn có thể sử dụng 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

cũng là giải pháp đệ quy cổ điển không phải là khó khăn hơn nhiều:

(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

Một cách khác để giải quyết vấn đề của bạn là qua Specter. Bạn cần một sự phụ thuộc khác sau đó, nhưng nó có thể là một thư viện hữu ích.

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

Bạn có thể mở rộng để thực hiện các thao tác phức tạp hơn. Đối với trường hợp sử dụng này Clojure bình thường là đủ tốt.

(specter/transform [TreeWalker] inc data) 
;; => [[[2 3] [4 5]] [[6 7] [8 9]] [10 11] 12] 
Các vấn đề liên quan