Fork me on GitHub
#specter
<
2017-07-11
>
mbjarland13:07:05

lets say I have the following data structure:

{:2010-12-31 [{:name "New Year's Eve", :date "2010-12-31", :observed "2010-12-31", :public true}],
 :2010-12-25 [{:name "Christmas Day", :date "2010-12-25", :observed "2010-12-24", :public true}],
 :2010-05-31 [{:name "Memorial Day", :date "2010-05-31", :observed "2010-05-31", :public true}],
 :2010-11-25 [{:name "Thanksgiving Day", :date "2010-11-25", :observed "2010-11-25", :public true}],
 :2010-09-06 [{:name "Labor Day", :date "2010-09-06", :observed "2010-09-06", :public true}],
 :2010-01-01 [{:name "New Year's Day", :date "2010-01-01", :observed "2010-01-01", :public true}],
 :2010-07-04 [{:name "Independence Day", :date "2010-07-04", :observed "2010-07-05", :public true}],
 :2010-11-11 [{:name "Veterans Day", :date "2010-11-11", :observed "2010-11-11", :public true}],
 :2010-02-15 [{:name "George Washington's Birthday", :date "2010-02-15", :observed "2010-02-15", :public true}],
 :2010-01-18 [{:name "Martin Luther King, Jr. Day", :date "2010-01-18", :observed "2010-01-18", :public true}],
 :2010-10-11 [{:name "Columbus Day", :date "2010-10-11", :observed "2010-10-11", :public true}]}
and I would like to apply a function to all the dates (root level key and :date and :observed in the inner map). I got as far as using multi-transform on the root level keys but I'm failing at writing the rest of the path expression. I can do the first level with:
(multi-transform [MAP-KEYS (terminal my-tranform-fn)] data)
how would I go about transforming the other two dates in the data?

mbjarland13:07:22

ok I think I got it, somebody please tell me if there is a better way:

(multi-transform [(multi-path [MAP-VALS ALL (multi-path [:date (terminal my-transform-fn)]
                                                        [:observed (terminal my-transform-fn)])]
                              [MAP-KEYS (terminal my-transform-fn)])] data)

nathanmarz14:07:56

@mbjarland this is better: (transform (multi-path MAP-KEYS [MAP-VALS ALL (multi-path :date :observed)]) my-transform-fn data)

nathanmarz14:07:22

multi-transform is more for when you have distinct transformations you want to run on the same structure

mbjarland14:07:07

: ) figured there would be a better way...so just transform....when would I use multi-transform?

nathanmarz14:07:04

e.g. (multi-transform [ALL (multi-path [:a (terminal inc)] [:b (terminal dec)])] data)

nathanmarz14:07:01

if the transformation functions are distinct and there's any shared navigation, multi-transform will be more efficient

mbjarland14:07:05

ah so forking paths which shared ancestry are a good candidate

nathanmarz14:07:05

in your case each date location is transformed the same way, so cleaner to navigate to each date as a single path

nathanmarz14:07:14

yes, that's right

mbjarland14:07:39

ok, got it...it seems to me every time I find an excuse to use specter a couple of things happen 1. half my code goes away 2. the end result is beautiful 3. I realize that at least for me, most of the hurdle in specter is to grok paths. Thanks for the pointers

schmee14:07:58

I’m sure this has been asked a million times, but can I use Specter to go from [{:a 1 :b 2} {:a 3 :b 4}] to {:a [1 3] :b [2 4]}?

nathanmarz16:07:09

@schmee that's a complete transformation, so should do that with reduce

madstap16:07:56

@schmee I remember seeing a one liner for that that was something like: (defn f [ms] (apply merge-with into (for [m ms, [k v] m] {k [v]})))

schmee17:07:12

roger, thanks for the input 👍

schmee23:07:44

is there a know issue with transform and transients?

schmee23:07:32

I’m getting

java.lang.IllegalAccessError: Transient used after persistent! call
	at clojure.lang.PersistentVector$TransientVector.ensureEditable(PersistentVector.java:548)
	at clojure.lang.PersistentVector$TransientVector.persistent(PersistentVector.java:559)
	at clojure.lang.PersistentVector$TransientVector.persistent(PersistentVector.java:518)
	at clojure.core$persistent_BANG_.invokeStatic(core.clj:3336)
	at clojure.core$persistent_BANG_.invoke(core.clj:3329)
	at com.rpl.specter.impl$terminal_STAR_.invokeStatic(impl.cljc:402)
	at com.rpl.specter.impl$terminal_STAR_.invoke(impl.cljc:400)
	at com.rpl.specter.impl$compiled_transform_STAR_$fn__16689.invoke(impl.cljc:410)
	at com.rpl.specter$reify__18110$next_fn__18116.invoke(specter.cljc:642)
	at com.rpl.specter.navs$eval17464$fn__17465.invoke(navs.cljc:261)
	at com.rpl.specter.navs$eval17420$fn__17421$G__17409__17428.invoke(navs.cljc:213)
	at com.rpl.specter$reify__18110.transform_STAR_(specter.cljc:651)
	at com.rpl.specter.impl$compiled_transform_STAR_.invokeStatic(impl.cljc:408)
	at com.rpl.specter.impl$compiled_transform_STAR_.invoke(impl.cljc:407)
when using (s/transform s/MAP-VALS persistent! stuff)

schmee23:07:02

where stuff is a map of keyword to transient vectors