Closed DjebbZ closed 6 years ago
You can write it like this:
(sp/multi-transform
[sp/ALL (sp/multi-path [:values (sp/map-key :a) (sp/terminal-val sp/NONE)]
[#(< (count (:values %)) 2) (sp/terminal-val sp/NONE)]
[#(not (identical? sp/NONE %)) (sp/terminal transform-a-map))]]
vector-of-maps)
Also note the use of map-key
which is much more efficient than what you were doing.
Thank you, haven't thought about identical?
.
To be honest my #{:a}
was a simplification, I'm trying to remove all map entries with keys not in a set of keywords. So the navigator of step 1 is like [sp/ALL :values sp/MAP-KEYS #(not (valid-keys %))]
. Haven't found a way to express this with Specter.
Similar question here.
AFAIK, multi-path
works well only when path are static. For example:
(let [m {:k1 1
:k2 2
:k3 3}]
(multi-transform [(multi-path [:k1 (terminal inc)]
[:k2 (terminal #(* % %))]
[:k3 (terminal dec)])]
m))
;; => {:k1 2, :k2 4, :k3 2}
This example is both elegant and effective, but when I want to multi-transform on a dynamic path, I have no idea what to do with specter, for example:
(let [m {:app1 {:k1 1}
:app2 {:k2 2}
:app3 {:k3 3}}
where1 #{[:app1 :k1] [:app2 :k2]}
where2 #{[:app3 :k3]}]
(multi-transform [(multi-path [where1 do-something]
[where2 do-sth-else])]
m))
@nathanmarz @DjebbZ any suggestions ? related: https://github.com/nathanmarz/specter/issues/248
@jiacai2050 Parameterized navigators are just functions, so you can use/compose them just like anything else:
(defn to-keypath [keys] (apply keypath keys))
(defn multi-keypath [keys-set] (transduce (map to-keypath) multi-path keys-set1))
(defn foo [m keys-set1 keys-set2]
(let [p1 (multi-keypath keys-set1)
p2 (multi-keypath keys-set2)]
(multi-transform
(multi-path [p1 do-something] [p2 do-sth-else])
m
)))
@nathanmarz That's awesome. I haven't realized navigators can be composed just like functions, this give so much power, I can't imagine how I spend my life writing Clojure without specter before.
Yesterday I watched your talk which teaches me a lot, and I suggest user->bank
demo should be added in README.md, or at least navigators composition should be introduced somewhere in README.
@jiacai2050 That's a good suggestion to add to #56
👍 I will check this issue later. It seems that specter-wiki repo is the preferred docs, but there's no mention in README, intended or something else ?
All the pages on the wiki are linked from the README
README contains links to https://github.com/nathanmarz/specter/wiki not https://github.com/nathanmarz/specter-wiki , is there any connection between them?
specter-wiki is the source for specter/wiki. The repository exists so people can make pull requests to it.
Gotcha, does this mean that after merge a PR, you will update the wiki page manually? If yes, it seems kind of awkward, why not just use the repo for docs?
No, it's not manual. It's just a git push
.
That makes sense. Thanks.
Hello,
I want to transform a vector of maps in several places :
The theoritical code looks like this :
However this code fails with
java.lang.ClassCastException: clojure.lang.Keyword cannot be cast to clojure.lang.Associative
After putting some
println
I found thatterminal
ing withsp/NONE
indeed putssp/NONE
for the next transform to operate. Which means mytransform-a-map
function fails when it receivessp/NONE
.I managed to make it work by putting the last step at the first position
(3-1-2))
but it's suboptimal since it will transform all maps instead of only those relevant. In fact Iquick-bench
with criterium the version that works and another version that just thread-last intosetval 1
setval 2
transform 3
and the thread-last version is slightly faster.My question is : is it possible to write an efficient and "logical" (keeping the order 1 2 3)
multi-transform
?