UNPKG

bucketing

Version:

group an array of items into buckets

127 lines (98 loc) 3.62 kB
# bucketing In two tiers, group an array of items into buckets. At its core this is not entirely dissimilar to [`lodash.groupBy`](https://lodash.com/docs/#groupBy), but with a few differences: - Two-tiered: `lodash.groupBy` expects one function that takes an item and generates a key. `bucketing` expects two functions: one that takes an item and generates a label, and one that takes a label and generates a key. This allows you to group objects by a complex object rather than strings, working around the fact that JavaScript objects can only have string or number keys. - Auxiliary structures: `lodash.groupBy` returns just the resulting grouping. `bucketing` returns the original items, a unique array of labels, the same usual buckets, as well as a map from key to label. This module works with JavaScript as well as TypeScript out of the box. ## Example Given the following book data: ```js const mg = {id: 'mg', name: 'Max Gladstone'}; const nm = {id: 'nm', name: 'Neve Maslakovic'}; const ww = {id: 'ww', name: 'Will Wight'}; const gf = {id: 'gf', name: 'Gillian Flynn'}; const books = [ {title: 'Four Roads Cross', author: mg}, {title: 'Gone Girl', author: gf}, {title: 'Soulsmith', author: ww}, {title: 'Regarding Ducks and Universes', author: nm}, {title: 'Two Serpents Rise', author: mg}, {title: 'Sharp Objects', author: gf}, ]; ``` We can group them by author on author ID: ```js import {group} from 'bucketing'; const groupings = group( books, book => book.author, author => author.id ); ``` This gives us: ```js // The original: groupings.items; // === books // The labels: groupings.labels; // equal to [mg, gf, ww, nm] // The buckets: groupings.keyToItems; /* equal to: { 'mg': [ {title: 'Four Roads Cross', author: mg}, {title: 'Two Serpents Rise', author: mg} ], 'gf': [ {title: 'Gone Girl', author: gf}, {title: 'Sharp Objects', author: gf} ], 'ww': [ {title: 'Soulsmith', author: ww}, ], 'nm': [ {title: 'Regarding Ducks and Universes', author: nm} ] } */ // The map: groupings.keyToLabel; /* equal to: { 'mg': {id: 'mg', name: 'Max Gladstone'}, 'gf': {id: 'gf', name: 'Gillian Flynn'}, 'ww': {id: 'ww', name: 'Will Wight'}, 'nm': {id: 'nm', name: 'Neve Maslakovic'} } */ ``` ## API ### `group<T, L>(items: T[], by: T => L, on: L => string): Grouping` Takes `items`, buckets them using the labels generated from the `by` function, and keys those labels using the keys generated from the `on` function. Returns a `Grouping`. Please ensure that the `on` function generates unique keys for a given label. That is to say: no two labels should share the same key. ### `Grouping<Item, Label>` The `Grouping<Item, Label>` type is the return type of `group`. It contains four things: - `items: Item[]`: the original array of items passed to `group` - `labels: Label[]`: a unique array of labels generated from the array of items. The key generated by the `on` function is used to determine label equality. - `keyToItems: ItemBuckets<Item>`: a map in which each key-value pair is a bucket. The key is the key of bucket's label, and the value is an array of items that all fall under said bucket. - `keyToLabel: LabelMap<Item>`: a map that maps from key to label. ### `ItemBuckets<Item>` A type defined as `{ [key: string]: Item[] }`. Conceptually an unordered list of buckets. Each bucket has a label (whose key is the bucket's key) and contains one or more items (in the bucket's value). ### `LabelMap<Label>` A type defined as `{ [key: string]: Label }`. Conceptually a map of keys to labels.