What's an efficient way to group a list by one of it's propertiies?


#1

I have several groupings I need to do today and find myself having a hard time finding a good way to do this in ReasonML. Here’s how I would group something in JS:

var groupBy = function(xs, keyFn) {
  return xs.reduce(function(rv, x) {
    const key = keyFn(x);
    (rv[x[key]] = rv[x[key]] || []).push(x);
    return rv;
  }, {});
};
console.log(groupBy(['one', 'two', 'three'], x=> x.length));
// => {3: ["one", "two"], 5: ["three"]}

#2

Hey. Did you figure it out? Here is something giving as efficient performance: https://reasonml.github.io/en/try.html?rrjsx=true&reason=NoAQRgzgdBCmB2ATAugAlgDwC6wE7wEMAbVRASwGMsAJAiVALlQAoApaAEUqyi2YHIAbgEoANKghZcZeAHNhqALwA+VGAD26kotQAiABZ0A8gHd4ABVzqADniwBPXQG4AUKEgwEKdNjyESuLCIAK4UsACCuLgE9owsBFExAgRiLPxg4vwpSqrpmWAKKqjpSnqBIWHOLi5EsFioslbB1gBCsTrMGBDiANaw9gBi8IWqAN4uqKjloRGJ9swTk6hdoouTzLiC4hgjqONLS7X1PaXuEMh9g-Cdwq4Hk2QAZizkVLQQG1uoPcIK+-cPWTwdSBNjQSLRexQazBCD6TridhQLhUKDBeAQAiPWAAcTqn16v1uayWAF90EQ4HsSQckSieHA+JteuJgAAfDBs5DEgGku73Tb8yakxGcbhQWAAW2sDmYwkWxL51SODSUi3ZunU8FgunEuiwJnUur0WH0gR1XMWbKgDSarXmzBtOxyEikMlkAH11I8PTI+ABlN1yKC1OSmm6-VwuAD0ACpUOFUEQyFgsLUfFICKh9LAiLZcKhY9GanVUI8QQBRAgUfQAaQAaqVmIhxI9dv86eLLh9EApragWrmeBCYlBy7gqzWAKrMR0-F1nZCPZg9UXI8XozHYvF8FvfImuJUuceTuv15iycSO77iEQupFEdSyABMK9vkaAA


#4

Here’s something that will work. It doesn’t return the map, though. I’m not sure if that’s critical for you.

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 () =
  [|"one", "two", "three"|]
  |> groupBy(~key=String.length)
  |. Belt.Array.forEach(Js.log);