ClojureDocs

Nav

Namespaces

zipper

clojure.zip

Available since 1.0
  • (zipper branch? children make-node root)
Creates a new zipper structure. 
 branch? is a fn that, given a node, returns true if can have
children, even if it currently doesn't.
 children is a fn that, given a branch node, returns a seq of its
children.
 make-node is a fn that, given an existing node and a seq of
children, returns a new branch node with the supplied children.
root is the root node.
4 Examples
;; Some clojure.zip functions will overwrite clojure.core's definitions
(use 'clojure.zip)

;; You may wish to require :as in order to avoid the above
(require '[clojure.zip :as z])

;; For the purposes of keeping the examples that follow clean,
;; assume we have taken the former route: (use 'clojure.zip)

(use 'clojure.pprint)
(def p pprint)

user> (def z [[1 2 3] [4 [5 6] 7] [8 9]])
#'user/z

user> (def zp (zipper vector? seq (fn [_ c] c) z))
#'user/zp

user> zp
[[[1 2 3] [4 [5 6] 7] [8 9]] nil]

user=> (p (-> zp down))
[[1 2 3]
 {:l [],
  :pnodes [[[1 2 3] [4 [5 6] 7] [8 9]]],
  :ppath nil,
  :r ([4 [5 6] 7] [8 9])}]
 
user> (first (-> zp down))
[1 2 3]

user=> (p (-> zp down right))
[[4 [5 6] 7]
 {:l [[1 2 3]],
  :pnodes [[[1 2 3] [4 [5 6] 7] [8 9]]],
  :ppath nil,
  :r ([8 9])}]

user> (first (-> zp down right))
[4 [5 6] 7]

user=> (p (-> zp down right down right))
[[5 6]
 {:l [4],
  :pnodes [[[1 2 3] [4 [5 6] 7] [8 9]] [4 [5 6] 7]],
  :ppath
  {:l [[1 2 3]],
   :pnodes [[[1 2 3] [4 [5 6] 7] [8 9]]],
   :ppath nil,
   :r ([8 9])},
  :r (7)}]

user=> (p (-> zp down right down right down))
[5
 {:l [],
  :pnodes [[[1 2 3] [4 [5 6] 7] [8 9]] [4 [5 6] 7] [5 6]],
  :ppath
  {:l [4],
   :pnodes [[[1 2 3] [4 [5 6] 7] [8 9]] [4 [5 6] 7]],
   :ppath
   {:l [[1 2 3]],
    :pnodes [[[1 2 3] [4 [5 6] 7] [8 9]]],
    :ppath nil,
    :r ([8 9])},
   :r (7)},
  :r (6)}]

user=> (p (-> zp down right down right (replace "hello")))
["hello"
 {:changed? true,
  :l [4],
  :pnodes [[[1 2 3] [4 [5 6] 7] [8 9]] [4 [5 6] 7]],
  :ppath
  {:l [[1 2 3]],
   :pnodes [[[1 2 3] [4 [5 6] 7] [8 9]]],
   :ppath nil,
   :r ([8 9])},
  :r (7)}]

user=> (p (-> zp down right down right (replace "hello") up))
[(4 "hello" 7)
 {:changed? true,
  :l [[1 2 3]],
  :pnodes [[[1 2 3] [4 [5 6] 7] [8 9]]],
  :ppath nil,
  :r ([8 9])}]

user=> (p (-> zp down right down right (replace "hello") up root))
([1 2 3] (4 "hello" 7) [8 9])
(require '[clojure.zip :as zip])

;; Adds zip support for maps.
;; (Source: http://stackoverflow.com/a/15020649/42188)
(defn map-zipper [m]
  (zip/zipper 
    (fn [x] (or (map? x) (map? (nth x 1))))
    (fn [x] (seq (if (map? x) x (nth x 1))))
    (fn [x children] 
      (if (map? x) 
        (into {} children) 
        (assoc x 1 (into {} children))))
    m))

(def m {:a 3 :b {:x true :y false} :c 4})

;; Note that hash-maps are not ordered:
(-> (map-zipper m) zip/down zip/right zip/node)
;;=> [:b {:y false, :x true}]

;; Treat nodes as [key value] pairs:
(-> (map-zipper m) 
    zip/down
    (zip/edit (fn [[k v]] [k (inc v)]))
    zip/root)
;;=> {:c 5, :b {:y false, :x true}, :a 3}
;; A version of  zipper that allows mixing maps and vectors 
;; Note that it traverses map entries too
(require '[clojure.zip :as z])
(defn map-vec-zipper [m]
  (z/zipper
    (fn [x] (or (map? x) (sequential? x)))
    seq
    (fn [p xs]
      (if (isa? (type p) clojure.lang.MapEntry)
        (into [] xs)
        (into (empty p) xs)))
    m))
(-> (map-vec-zipper [{1 [21 22] 3 [4]}])
  z/down
  (z/edit assoc :e 99)
  z/down
  ;; Note that the map does not guarantee particular entries ordering.
  z/down ;; Getting into map entry. 
  z/next
  (z/edit conj 77)
  z/root)
;;=> [{1 [21 22 77], 3 [4], :e 99}]
;; Get sequence of all visited nodes
(require '[clojure.zip :as z])
(->> (z/vector-zip [[1 2] 3 [[4 5]]])
  (iterate z/next)
  (take-while #(not (z/end? %))) ;; Zipper's "end of iteration" condition. 
  (map z/node))
;;=> ([[1 2] 3 [[4 5]]] 
;;    [1 2] 
;;    1 2
;;    3 
;;    [[4 5]] 
;;    [4 5]
;;    4 5)
See Also

Returns the loc of the leftmost child of the node at this loc, or nil if no children

Added by Claj

Returns the loc of the parent of the node at this loc, or nil if at the top

Added by Claj

Returns the loc of the right sibling of the node at this loc, or nil

Added by Claj

Returns the loc of the left sibling of the node at this loc, or nil

Added by boxie

Returns a seq of the children of node at loc, which must be a branch

Added by boxie

Returns the node at loc

Added by abrooks

Replaces the node at this loc, without moving

Added by phreed
3 Notes