2017-07-14 26 views
5

Mam wektor [[[1 2] [3 4]] [[5 6] [7 8]] [9 10] 11]. Chcę zastosować funkcję do tego wektora, ale zachować strukturę danych.Clojure - zastosowanie funkcji do wektora wektorów

Na przykład chcę dodać 1 do każdej liczby, ale zachować strukturę danych, aby uzyskać wynik: [[[2 3] [4 5]] [[6 7] [8 9]] [10 11] 12]. czy to możliwe?

Próbowałem

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

Ale widać, że struktura danych nie jest taka sama.

Czy może to funkcja, która bierze (2 3 4 5 6 7 8 9 10 11 12) do [[[2 3] [4 5]] [[6 7] [8 9]] [10 11] 12]

Myślałem, że może używać postwalk ale nie jestem pewien, czy to jest prawidłowe.

Każda pomoc będzie mile widziane

Odpowiedz

6

Można użyć 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

również klasyczne rozwiązanie rekurencyjne nie jest dużo trudniejsze:

(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

Innym sposobem rozwiązania problemu jest przez Specter. W takim przypadku potrzebna jest inna zależność, ale może to być przydatna biblioteka.

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

Można go rozszerzyć, aby wykonać bardziej skomplikowane operacje. W tym przypadku normalne Clojure jest wystarczająco dobre.

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