block by joyrexus 9837596

Nested grouping of arrays

nest.js

A multi-level groupBy for arrays inspired by D3’s nest operator.

Nesting allows elements in an array to be grouped into a hierarchical tree structure; think of it like the GROUP BY operator in SQL, except you can have multiple levels of grouping, and the resulting output is a tree rather than a flat table. The levels in the tree are specified by key functions.

See this fiddle for live demo.

Implementation

Depends on lodash’s groupBy and mapValues:

_ = require('lodash');

var nest = function (seq, keys) {
    if (!keys.length)
        return seq;
    var first = keys[0];
    var rest = keys.slice(1);
    return _.mapValues(_.groupBy(seq, first), function (value) { 
        return nest(value, rest)
    });
};

module.exports = nest;

Usage

Input data to be nested:

var data = [
  { type: "apple", color: "green", quantity: 1000 }, 
  { type: "apple", color: "red", quantity: 2000 }, 
  { type: "grape", color: "green", quantity: 1000 }, 
  { type: "grape", color: "red", quantity: 4000 }
];

Key functions used for grouping criteria:

var byType = function(d) {
  return d.type;
};

var byColor = function(d) {
  return d.color;
};

var byQuantity = function(d) {
  return d.quantity;
};

First Example

Expected output when grouping by color and quantity:

var expected = {
  green: {
    "1000": [
      { type: 'apple', color: 'green', quantity: 1000 }, 
      { type: 'grape', color: 'green', quantity: 1000 }
    ]
  },
  red: {
    "2000": [
      { type: 'apple', color: 'red', quantity: 2000 }
    ],
    "4000": [
      { type: 'grape', color: 'red', quantity: 4000 }
    ]
  }
};

Nest by key name:

deepEqual(nest(data, ['color', 'quantity']), expected);

Nest by key functions:

deepEqual(nest(data, [byColor, byQuantity]), expected);

Second Example

Expected output when grouping by type and color:

expected = {
  apple: {
    green: [ { "type": "apple", "color": "green", "quantity": 1000 } ],
    red: [ { "type": "apple", "color": "red", "quantity": 2000 } ]
  },
  grape: {
    green: [ { "type": "grape", "color": "green", "quantity": 1000 } ],
    red: [ { "type": "grape", "color": "red", "quantity": 4000 } ]
  }
};

Nest by key names:

deepEqual(nest(data, ['type', 'color']), expected);

Nest by key functions:

deepEqual(nest(data, [byType, byColor]), expected);

demo.js

nest.js