const assert = require('assert') const _ = require('lodash') const d = [ // test data {x: 1, y: 1, z: 'a'}, {x: 1, y: 1, z: 'b'}, {x: 2, y: 1, z: 'c'}, {x: 2, y: 2, z: 'd'}, {x: 2, y: 3, z: 'e'}, {x: 3, y: 1, z: 'f'} ] const e = [ // expected result {k1: 1, k2: 1, data: [{x: 1, y: 1, z: 'a'}, {x: 1, y: 1, z: 'b'}]}, {k1: 2, k2: 1, data: [{x: 2, y: 1, z: 'c'}]}, {k1: 2, k2: 2, data: [{x: 2, y: 2, z: 'd'}]}, {k1: 2, k2: 3, data: [{x: 2, y: 3, z: 'e'}]}, {k1: 3, k2: 1, data: [{x: 3, y: 1, z: 'f'}]} ] function genrows(groups, groupKey) { return _.toPairs(groups) .map(([key, data]) => ({[groupKey]: key, data})) } function gengroups(arr, iteratee, key) { const grouped = _.groupBy(arr, iteratee) return genrows(grouped, key) } function grouparray(data, props) { let result = [{data}] props.map((prop, i) => { const key = prop.key || `k${i + 1}` const iteratee = prop.iteratee || prop result = _.flatten(result.map(row => { return gengroups(row.data, iteratee, key) .map(group => Object.assign({}, row, { [key]: group[key], data: group.data })) })) }) return _.flatten(result) } console.log('final', grouparray(d, ['x', 'y'])) // e[0].data[0].x = 274 assert.deepEqual(grouparray(d, ['x', { iteratee: (data) => data.y }]), e) console.log('deepEqual', true) // console.log('expected full', JSON.stringify(e, null, ' ')) // console.log('final full', JSON.stringify(grouparray(d, ['x', 'y']), null, ' ')) const exptected = [ { "k1": 1, "k2": 1, "data": [ { "x": 1, "y": 1, "z": "a" }, { "x": 1, "y": 1, "z": "b" } ] }, { "k1": 2, "k2": 1, "data": [ { "x": 2, "y": 1, "z": "c" } ] }, { "k1": 2, "k2": 2, "data": [ { "x": 2, "y": 2, "z": "d" } ] }, { "k1": 2, "k2": 3, "data": [ { "x": 2, "y": 3, "z": "e" } ] }, { "k1": 3, "k2": 1, "data": [ { "x": 3, "y": 1, "z": "f" } ] } ] const final = [ { "data": [ { "x": 1, "y": 1, "z": "a" }, { "x": 1, "y": 1, "z": "b" } ], "k1": "1", "k2": "1" }, { "data": [ { "x": 2, "y": 1, "z": "c" } ], "k1": "2", "k2": "1" }, { "data": [ { "x": 2, "y": 2, "z": "d" } ], "k1": "2", "k2": "2" }, { "data": [ { "x": 2, "y": 3, "z": "e" } ], "k1": "2", "k2": "3" }, { "data": [ { "x": 3, "y": 1, "z": "f" } ], "k1": "3", "k2": "1" } ]