diff --git a/README.md b/README.md index 3a1b0dad..bc21038e 100644 --- a/README.md +++ b/README.md @@ -417,6 +417,10 @@ This produces: Equivalent to [group](#group), but returns nested arrays instead of nested maps. +# d3.flatGroup(iterable, ...keys) · [Source](https://github.com/d3/d3-array/blob/master/src/group.js), [Examples](https://observablehq.com/@d3/d3-flatgroup) + +Equivalent to [group](#group), but returns the result as a flat array of [key0, key1, …, values] instead of nested maps. + # d3.index(iterable, ...keys) · [Source](https://github.com/d3/d3-array/blob/master/src/group.js), [Examples](https://observablehq.com/@d3/d3-group) Equivalent to [group](#group) but returns a unique value per compound key instead of an array, throwing if the key is not unique. @@ -507,6 +511,10 @@ To convert a Map to an Array, use [Array.from](https://developer.mozilla.org/en- Equivalent to [rollup](#rollup), but returns nested arrays instead of nested maps. +# d3.flatRollup(iterable, ...keys) · [Source](https://github.com/d3/d3-array/blob/master/src/group.js), [Examples](https://observablehq.com/@d3/d3-flatgroup) + +Equivalent to [rollup](#rollup), but returns the result as a flat array of [key0, key1, …, reduced value] instead of nested maps. + # d3.groupSort(iterable, comparator, key) · [Source](https://github.com/d3/d3-array/blob/master/src/groupSort.js), [Examples](https://observablehq.com/@d3/d3-groupsort)
# d3.groupSort(iterable, accessor, key) diff --git a/src/group.js b/src/group.js index 4814571f..0c30d7e9 100644 --- a/src/group.js +++ b/src/group.js @@ -9,14 +9,21 @@ export function groups(values, ...keys) { return nest(values, Array.from, identity, keys); } -export function flatGroup(values, ...keys) { - let groups = groups(values, ...keys); +function flatten(groups, keys) { for (let i = 1, n = keys.length; i < n; ++i) { groups = groups.flatMap(g => g.pop().map(([key, value]) => [...g, key, value])); } return groups; } +export function flatGroup(values, ...keys) { + return flatten(groups(values, ...keys), keys); +} + +export function flatRollup(values, reduce, ...keys) { + return flatten(rollups(values, reduce, ...keys), keys); +} + export function rollup(values, reduce, ...keys) { return nest(values, identity, reduce, keys); } diff --git a/src/index.js b/src/index.js index 44c5ac66..209d7b2f 100644 --- a/src/index.js +++ b/src/index.js @@ -8,7 +8,7 @@ export {default as descending} from "./descending.js"; export {default as deviation} from "./deviation.js"; export {default as extent} from "./extent.js"; export {Adder, fsum, fcumsum} from "./fsum.js"; -export {default as group, groups, index, indexes, rollup, rollups} from "./group.js"; +export {default as group, flatGroup, flatRollup, groups, index, indexes, rollup, rollups} from "./group.js"; export {default as groupSort} from "./groupSort.js"; export {default as bin, default as histogram} from "./bin.js"; // Deprecated; use bin. export {default as thresholdFreedmanDiaconis} from "./threshold/freedmanDiaconis.js"; diff --git a/test/group-test.js b/test/group-test.js index 24eaa7b3..1909f069 100644 --- a/test/group-test.js +++ b/test/group-test.js @@ -1,5 +1,5 @@ import assert from "assert"; -import {group} from "../src/index.js"; +import {group, flatGroup, flatRollup} from "../src/index.js"; const data = [ {name: "jim", amount: "34.0", date: "11/12/2015"}, @@ -129,6 +129,41 @@ it("group(data, accessor) interns keys", () => { assert.strictEqual([...map.keys()][1], b); }); +it("flatGroup(data, accessor, accessor) returns the expected array", () => { + assert.deepStrictEqual( + flatGroup(data, d => d.name, d => d.amount), + [ + ['jim', '34.0', [{name: 'jim', amount: '34.0', date: '11/12/2015'}]], + ['carl', '120.11', [{name: 'carl', amount: '120.11', date: '11/12/2015'}]], + ['stacy', '12.01', [{name: 'stacy', amount: '12.01', date: '01/04/2016'}]], + ['stacy', '34.05', [{name: 'stacy', amount: '34.05', date: '01/04/2016'}]] + ] + ); +}); + +it("flatRollup(data, reduce, accessor) returns the expected array", () => { + assert.deepStrictEqual( + flatRollup(data, v => v.length, d => d.name), + [ + ['jim', 1], + ['carl', 1], + ['stacy', 2] + ] + ); +}); + +it("flatRollup(data, reduce, accessor, accessor) returns the expected array", () => { + assert.deepStrictEqual( + flatRollup(data, v => v.length, d => d.name, d => d.amount), + [ + ['jim', '34.0', 1], + ['carl', '120.11', 1], + ['stacy', '12.01', 1], + ['stacy', '34.05', 1] + ] + ); +}); + function entries(map, depth) { if (depth > 0) { return Array.from(map, ([k, v]) => [k, entries(v, depth - 1)]);