Imho, there’s really no need for map/reduce, this can be done with good old JS Array forEach:
module Input = {
type item = {id: int, name: string, groupName: string}
}
module Output = {
type item = {id: int, name: string}
type groupedItems = {group: string, items: array<item>}
let item = ({Input.id: id, name}) => {id, name}
}
let group = items => {
module Arr = Js.Array2
module Dict = Js.Dict
let map = Dict.empty()
items->Arr.forEach(item => {
let name = item.Input.groupName
switch map->Dict.get(name) {
| Some({Output.items, _}) =>
items->Arr.push(Output.item(item))->ignore
| None =>
map->Dict.set(name, {Output.group: name, items: [Output.item(item)]})
}
})
map->Dict.values
}
This is using an object as a map of group names to grouped items, and mutating the group arrays internally, but the mutation is not visible to the outside world. At the end we just return an array of groupedItems that was required.
I’m accepting @yawaramin’s answer because it’s more readable and more approachable for incoming JS developers, even though I had asked for a Belt API based answer.