I’m looking for a way to keep order of my Belt.Map (Map.String), I use Map to simply map/get and merge another Map but I need to keep the initial order:
let first = Belt.Map.String.fromArray([("b", {"any": "value"}), ("a", {"any": "value"})])
Js.log(first->Belt.Map.String.toArray) // => [["a",{"any":"value"}],["b",{"any":"value"}]]
let second = Belt.Map.String.fromArray([("c", {"any": "value"}), ("b", {"any": "new value"})])
let all = Belt.Map.String.merge(first, second, (_key, a, b) => {
switch b {
| Some(b) => Some(b)
| None =>
switch a {
| Some(a) => Some(a)
| None => None
}
}
})
Js.log(all->Belt.Map.String.toArray) // => [["a",{"any":"value"}],["b",{"any":"new value"}],["c",
{"any":"value"}]]
I need to have b,a,c
Is there a way to keep initial order or should I better use a simple array and merge by myself
The Belt.Map structure uses an AVL tree internally which relies on sorting the keys. So it’s not possible for it to remember the insertion order.
One alternative is to use a list with Belt.List.getAssoc and Belt.List.setAssoc. These treat your list like a more basic kind of “map” which AFAIK will preserve insertion order. It’s probably similar to what you would do with using an array.
Note that the Belt maps use an AVL tree because it makes looking up items much more performant. Belt.Map.String.get will be more efficient than Belt.List.getAssoc. This is one of the tradeoffs you make when choosing a data structure.
If you need to preserve insertion order, then I assume you’re using your map with forEach or reduce to generate some other kind of value from it? In that case, a list (or an array) may be a better choice anyway.
Thx for the explaination.
Belt.List work but I would have preferred an easiest way to merge two occurence.
setAssoc force me to do a forEach on my “second” list to add item one by one to the “first” one.