Skip to content

Instantly share code, notes, and snippets.

@eneroth
Last active August 3, 2020 14:09
Show Gist options
  • Save eneroth/0e6d2f4ab5cd87a18ff745cbbaf36e9a to your computer and use it in GitHub Desktop.
Save eneroth/0e6d2f4ab5cd87a18ff745cbbaf36e9a to your computer and use it in GitHub Desktop.
(ns example
(:require [com.rpl.specter :as sp]))
;; Find paths
;; #######################################
(defn find-when
"Given a nested data structure and a predicate, return a vector of
paths to all locations where the predicate is true."
[data pred]
(let [walker (sp/recursive-path [] p
(sp/cond-path
;; If a vector is encountered
sequential?
[sp/INDEXED-VALS
(sp/if-path [sp/LAST (sp/pred pred)]
sp/FIRST
[(sp/collect-one sp/FIRST) sp/LAST p])]
;; If a map is encountered
map?
[sp/ALL
(sp/if-path [sp/LAST (sp/pred pred)]
sp/FIRST
[(sp/collect-one sp/FIRST) sp/LAST p])]))
ret (sp/select walker data)]
;; If a non-vector path is returned (i.e., just one value)
;; Wrap it in a vector
(mapv #(if-not (vector? %) (vector %) %) ret)))
;; Example
(comment
(def example-data
{:lucky-number 17
:a-vector [10 20]
:more-data [:im-not-a-number
"Me neither"
[{:dog 3} [:cat 1] "hello world" 2]
30
1/2
{:level-one [0
{:level-two 3}]}]})
(find-when example-data number?)
;; Result
[[:lucky-number]
[:a-vector 0]
[:a-vector 1]
[:more-data 2 0 :dog]
[:more-data 2 1 1]
[:more-data 2 3]
[:more-data 3]
[:more-data 4]
[:more-data 5 :level-one 0]
[:more-data 5 :level-one 1 :level-two]]
#__)
;; Transform values
;; #######################################
(defn transform-when
"Given a nested data structure, a predicate, and a function, run the function at each
location where the predicate is true, then return the data structure."
[data pred f]
(let [walker (sp/recursive-path [] p
(sp/cond-path
pred sp/STAY
sequential? [sp/ALL p]
map? [sp/ALL p]))]
(sp/transform walker f data)))
;; Examples
(comment
(def example-data
{:lucky-number 17
:a-vector [10 20]
:more-data [:im-not-a-number
"Me neither"
[{:dog 3} [:cat 1] "hello world" 2]
30
1/2
{:level-one [0
{:level-two 3}]}]})
(transform-when example-data number? inc)
;; Result
{:lucky-number 18
:a-vector [11 21]
:more-data [:im-not-a-number
"Me neither"
[{:dog 4} [:cat 2] "hello world" 3]
31
3/2
{:level-one [1
{:level-two 4}]}]}
(transform-when example-data keyword? name)
;; Result
{"lucky-number" 17
"a-vector" [10 20]
"more-data" ["im-not-a-number"
"Me neither"
[{"dog" 3} ["cat" 1] "hello world" 2]
30
1/2
{"level-one" [0
{"level-two" 3}]}]}
#__)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment