Fork me on GitHub
#specter
<
2017-11-21
>
johanatan22:11:59

hi, i have a normalized map say: version -> entity_1 -> entity_2 and I want to transform it into: entity_1 -> version -> entity_2. what is the best way to do this using specter?

johanatan22:11:14

[this is a map of maps of maps]

johanatan22:11:25

for example: input:

{1 {"e1" {"p1" nil "p2" 9} "e2" {"p3" nil "p4" 6}} 2 {"e1" {"p6" nil "p7" nil}}}
output:
{"e1" {1 {"p1" nil "p2" 9} 2 {"p6" nil "p7" nil}} "e2" {1 {"p3" nil, "p4" 6}}}

nathanmarz22:11:22

@johanatan specter won't help that much with that since you're basically making a whole new data structure

nathanmarz22:11:56

specter is for when you're changing part of a data structure, or changing many pieces the same way within the overall structure

johanatan22:11:38

well, i could do it with a transform/collect/map combo

johanatan22:11:46

but that isn't much better than just doing it by hand in pure clj

johanatan22:11:08

but i fail to see how in principle the "whole" isn't just an all-encompassing "part"

johanatan22:11:47

i.e., with any transformation-based language (say e.g. XSLT) changing the whole is just changing like changing a part where the part == the whole

johanatan22:11:02

in other words, it probably is possible with specter (and I would wager that the ultimate solution to it ends up being rather elegant once discovered) but the solution, like many (most?) in specter, is elusive and mind-bending to try to arrive at

nathanmarz22:11:06

I don't think there's an elegant specter solution to this

nathanmarz22:11:25

this is a total restructuring

nathanmarz22:11:46

that it's still a map -> map -> map afterwards is deceiving

johanatan22:11:47

you may be right. 🙂

johanatan22:11:03

at least i know to not spend too much time searching for it lol

nathanmarz22:11:27

it is an interesting use case

johanatan23:11:45

this works:

(apply deep-merge (for [[version events] in] (specter/transform [specter/MAP-VALS] #(do {version %}) events)))

johanatan23:11:12

where deep-merge is defined as:

(defn deep-merge
  [& vals]
  (if (every? map? vals)
    (apply merge-with deep-merge vals)
    (last vals)))

madstap20:11:38

Where specter isn't that well suited for this kind of transformation, there's this cool lib I remember seeing that should be perfect. https://github.com/disalvjn/faconne

madstap20:11:28

The same thing in faconne

(require '[faconne.core :as fac])

(def f (fac/transformer {v {e1 {e2 x}}} {e1 {v {e2 x}}}))

johanatan23:11:52

That's probably about as good/elegant as can be expected...