Skip to content

Instantly share code, notes, and snippets.

@fakenickels
Created May 20, 2019 22:12
Show Gist options
  • Save fakenickels/38947f92db35891dd3cb74b7ae640707 to your computer and use it in GitHub Desktop.
Save fakenickels/38947f92db35891dd3cb74b7ae640707 to your computer and use it in GitHub Desktop.
/* actually there is a way to do this with reduce + find but would be really expensive if there are too many elements */
/* Really don't bother with all these now, it's just some optimizations you can do with BuckleScript */
let groupBy = (type a, items, ~key) => {
let cmp: (a, a) => int = Pervasives.compare;
module Cmp = (val Belt.Id.comparable(~cmp));
let empty = Belt.Map.make(~id=(module Cmp));
let merge = newItem =>
fun
| None => Some([newItem])
| Some(existingItems) => Some([newItem, ...existingItems]);
Belt.Array.reduce(items, empty, (map, item) =>
Belt.Map.update(map, key(item), merge(item))
)
|. Belt.Map.map(Array.of_list)
|> Belt.Map.toArray;
};
let group = (user##events)->groupBy(~key=(event => formatDate(event##date)));
if would return something like
[|("20-20-2020", [|event1, event2, event3|]), ("12-20-1202", [|event3, event4, event5|])|]
which you can loop like
result
->Belt.Array.map((( label, events )) => {
<Group key={label}>
<Title value=label />
{events->Belt.Array.map(event, renderEventItem)->React.Array}
</Group>
})
->React.array
```
the other "unoptimized" way would be something like
```
let groupBy = (items, ~key) => {
items->Belt.Array.reduce([||], (acc, item) => {
let itemKey = key(item);
let group = Belt.Array.getBy(acc, ((label, _)) => label == itemKey)
let newGroup = switch(group) {
| Some(( itemKey, currentEls )) => (group, Belt.Array.concat(currentEls, [|item|]))
| None => (itemKey, [|item|])
}
acc->Belt.Array.keep(((label, _)) => label !== itemKey)->Belt.Array.concat(group)
})
}
Or with a custom getIndex
let getIndex = (items, ~predicate) => {
let length = Belt.Array.length(items);
let rec find = index =>
if (index > length) {
None;
} else {
/* Fine because we are hiding the unsafe implementation from the user/implementer */
let el = Belt.Array.getUnsafe(items, index);
predicate(el) ? Some(index) : find(index + 1);
};
find(0);
};
let groupBy = (items, ~key) => {
items->Belt.Array.reduce([||], (acc, item) => {
let itemKey = key(item);
let groupIndex = getIndex(acc, ((label, _)) => label == itemKey)
switch(groupIndex) {
| Some(index) => get group concat index... and use Belt.Array.set
| None => Belt.Array.concat(acc, (itemKey, [|item|]))
}
})
}
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment