redplanetlabs / specter

Clojure(Script)'s missing piece
Apache License 2.0
2.51k stars 102 forks source link

Question: how to achieve assoc-in but preserve key order? #281

Closed rlhk closed 5 years ago

rlhk commented 5 years ago

Hi, I've been using Specter for a while and it's amazing. But I am now stuck with one use case:

Given a map m1:

{:a {:x   {:y "yen"}
     :x_1 {:y "yen"}
     :z "dollar"}}

Now I wanted to insert a kv so that the result is:

{:a {:x   {:y "yen"}
     :x_1 {:y "yen"}
     :x_2 {:y "yen"}
     :z "dollar"}}

This can be done by (assoc-in m-1 [:a :x_2] {:y "yen"}) if I don't care the key order. Since Specter claims to preserve data structure, I suppose there is a way to ensure inserting :x_2 right after :x_1 when I get the keys of the map @ path [:a]. Is it possible?

nathanmarz commented 5 years ago

I think you just want the inner structure to be a sorted map? As long as its a sorted map, then the Specter transform will also be sorted. You can make sure the inner map is created as sorted with a path like [:a (nil->val (sorted-map)) :b]

rlhk commented 5 years ago

No, the inner structure is not and not intended to be a sorted map. It's just a normal map as defined. The point is (keys {:a "ape" :b "ban" :c "can"}) & (keys {:a "ape" :c "can" :b "ban"}) are (:a :b :c) (:a :c :b) respectively

Say if the initial map is {:a "ape" :b "ban" :c "can"}, I want to insert a kv say [:b1 "B1"] after key :b such that the result is {:a "ape" :b "ban" :b1 "B1" :c "can"} instead of adding to the end by assoc-in as {:a "ape" :b "ban" :c "can" :b1 "B1"}.

So I need a way to be able to specify which key to insert after. Is this possible?

rlhk commented 5 years ago

Played a bit and realised that new keys added by assoc-in won't gaurantee to be at the end of the map sequence. Relying on natural map key order looks like a bad idea. Closing. Thanks!