@tidyjs/tidy 2.5.2 → 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/addRows.js.map +1 -1
- package/dist/es/arrange.js +9 -5
- package/dist/es/arrange.js.map +1 -1
- package/dist/es/complete.js.map +1 -1
- package/dist/es/count.js +6 -2
- package/dist/es/count.js.map +1 -1
- package/dist/es/debug.js +4 -2
- package/dist/es/debug.js.map +1 -1
- package/dist/es/distinct.js +3 -3
- package/dist/es/distinct.js.map +1 -1
- package/dist/es/expand.js +18 -13
- package/dist/es/expand.js.map +1 -1
- package/dist/es/fill.js +10 -3
- package/dist/es/fill.js.map +1 -1
- package/dist/es/filter.js.map +1 -1
- package/dist/es/fullJoin.js +23 -20
- package/dist/es/fullJoin.js.map +1 -1
- package/dist/es/groupBy.js +56 -28
- package/dist/es/groupBy.js.map +1 -1
- package/dist/es/helpers/assignGroupKeys.js +4 -4
- package/dist/es/helpers/assignGroupKeys.js.map +1 -1
- package/dist/es/helpers/groupMap.js +2 -2
- package/dist/es/helpers/groupMap.js.map +1 -1
- package/dist/es/helpers/groupTraversal.js +5 -4
- package/dist/es/helpers/groupTraversal.js.map +1 -1
- package/dist/es/helpers/identity.js.map +1 -1
- package/dist/es/helpers/isObject.js.map +1 -1
- package/dist/es/helpers/keysFromItems.js +1 -2
- package/dist/es/helpers/keysFromItems.js.map +1 -1
- package/dist/es/helpers/singleOrArray.js.map +1 -1
- package/dist/es/helpers/summation.js +11 -3
- package/dist/es/helpers/summation.js.map +1 -1
- package/dist/es/innerJoin.js +37 -12
- package/dist/es/innerJoin.js.map +1 -1
- package/dist/es/item/rate.js +2 -3
- package/dist/es/item/rate.js.map +1 -1
- package/dist/es/leftJoin.js +13 -8
- package/dist/es/leftJoin.js.map +1 -1
- package/dist/es/map.js.map +1 -1
- package/dist/es/math/math.js.map +1 -1
- package/dist/es/mutate.js +1 -1
- package/dist/es/mutate.js.map +1 -1
- package/dist/es/mutateWithSummary.js +1 -1
- package/dist/es/mutateWithSummary.js.map +1 -1
- package/dist/es/pivotLonger.js +31 -7
- package/dist/es/pivotLonger.js.map +1 -1
- package/dist/es/pivotWider.js +24 -19
- package/dist/es/pivotWider.js.map +1 -1
- package/dist/es/rename.js.map +1 -1
- package/dist/es/replaceNully.js +1 -1
- package/dist/es/replaceNully.js.map +1 -1
- package/dist/es/select.js +3 -3
- package/dist/es/select.js.map +1 -1
- package/dist/es/selectors/contains.js.map +1 -1
- package/dist/es/selectors/endsWith.js.map +1 -1
- package/dist/es/selectors/everything.js.map +1 -1
- package/dist/es/selectors/matches.js.map +1 -1
- package/dist/es/selectors/negate.js +2 -2
- package/dist/es/selectors/negate.js.map +1 -1
- package/dist/es/selectors/numRange.js.map +1 -1
- package/dist/es/selectors/startsWith.js.map +1 -1
- package/dist/es/sequences/fullSeq.js +5 -1
- package/dist/es/sequences/fullSeq.js.map +1 -1
- package/dist/es/slice.js +2 -3
- package/dist/es/slice.js.map +1 -1
- package/dist/es/summarize.js +6 -4
- package/dist/es/summarize.js.map +1 -1
- package/dist/es/summary/deviation.js.map +1 -1
- package/dist/es/summary/first.js.map +1 -1
- package/dist/es/summary/last.js.map +1 -1
- package/dist/es/summary/max.js.map +1 -1
- package/dist/es/summary/mean.js.map +1 -1
- package/dist/es/summary/meanRate.js.map +1 -1
- package/dist/es/summary/median.js.map +1 -1
- package/dist/es/summary/min.js.map +1 -1
- package/dist/es/summary/n.js.map +1 -1
- package/dist/es/summary/nDistinct.js +2 -2
- package/dist/es/summary/nDistinct.js.map +1 -1
- package/dist/es/summary/sum.js.map +1 -1
- package/dist/es/summary/variance.js.map +1 -1
- package/dist/es/tally.js +4 -2
- package/dist/es/tally.js.map +1 -1
- package/dist/es/tidy.js.map +1 -1
- package/dist/es/total.js.map +1 -1
- package/dist/es/transmute.js.map +1 -1
- package/dist/es/vector/cumsum.js.map +1 -1
- package/dist/es/vector/lag.js +1 -1
- package/dist/es/vector/lag.js.map +1 -1
- package/dist/es/vector/lead.js +1 -1
- package/dist/es/vector/lead.js.map +1 -1
- package/dist/es/vector/roll.js +1 -1
- package/dist/es/vector/roll.js.map +1 -1
- package/dist/es/vector/rowNumber.js.map +1 -1
- package/dist/es/when.js +1 -2
- package/dist/es/when.js.map +1 -1
- package/dist/lib/addRows.js +0 -2
- package/dist/lib/addRows.js.map +1 -1
- package/dist/lib/arrange.js +9 -7
- package/dist/lib/arrange.js.map +1 -1
- package/dist/lib/complete.js +0 -2
- package/dist/lib/complete.js.map +1 -1
- package/dist/lib/count.js +6 -4
- package/dist/lib/count.js.map +1 -1
- package/dist/lib/debug.js +4 -4
- package/dist/lib/debug.js.map +1 -1
- package/dist/lib/distinct.js +3 -5
- package/dist/lib/distinct.js.map +1 -1
- package/dist/lib/expand.js +18 -15
- package/dist/lib/expand.js.map +1 -1
- package/dist/lib/fill.js +10 -5
- package/dist/lib/fill.js.map +1 -1
- package/dist/lib/filter.js +0 -2
- package/dist/lib/filter.js.map +1 -1
- package/dist/lib/fullJoin.js +22 -21
- package/dist/lib/fullJoin.js.map +1 -1
- package/dist/lib/groupBy.js +56 -30
- package/dist/lib/groupBy.js.map +1 -1
- package/dist/lib/helpers/assignGroupKeys.js +4 -6
- package/dist/lib/helpers/assignGroupKeys.js.map +1 -1
- package/dist/lib/helpers/groupMap.js +2 -4
- package/dist/lib/helpers/groupMap.js.map +1 -1
- package/dist/lib/helpers/groupTraversal.js +5 -6
- package/dist/lib/helpers/groupTraversal.js.map +1 -1
- package/dist/lib/helpers/identity.js +0 -2
- package/dist/lib/helpers/identity.js.map +1 -1
- package/dist/lib/helpers/isObject.js +0 -2
- package/dist/lib/helpers/isObject.js.map +1 -1
- package/dist/lib/helpers/keysFromItems.js +1 -4
- package/dist/lib/helpers/keysFromItems.js.map +1 -1
- package/dist/lib/helpers/singleOrArray.js +0 -2
- package/dist/lib/helpers/singleOrArray.js.map +1 -1
- package/dist/lib/helpers/summation.js +10 -4
- package/dist/lib/helpers/summation.js.map +1 -1
- package/dist/lib/index.js +0 -2
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/innerJoin.js +38 -14
- package/dist/lib/innerJoin.js.map +1 -1
- package/dist/lib/item/rate.js +2 -5
- package/dist/lib/item/rate.js.map +1 -1
- package/dist/lib/leftJoin.js +12 -9
- package/dist/lib/leftJoin.js.map +1 -1
- package/dist/lib/map.js +0 -2
- package/dist/lib/map.js.map +1 -1
- package/dist/lib/math/math.js +0 -2
- package/dist/lib/math/math.js.map +1 -1
- package/dist/lib/mutate.js +1 -3
- package/dist/lib/mutate.js.map +1 -1
- package/dist/lib/mutateWithSummary.js +1 -3
- package/dist/lib/mutateWithSummary.js.map +1 -1
- package/dist/lib/pivotLonger.js +31 -9
- package/dist/lib/pivotLonger.js.map +1 -1
- package/dist/lib/pivotWider.js +24 -21
- package/dist/lib/pivotWider.js.map +1 -1
- package/dist/lib/rename.js +0 -2
- package/dist/lib/rename.js.map +1 -1
- package/dist/lib/replaceNully.js +1 -3
- package/dist/lib/replaceNully.js.map +1 -1
- package/dist/lib/select.js +3 -5
- package/dist/lib/select.js.map +1 -1
- package/dist/lib/selectors/contains.js +0 -2
- package/dist/lib/selectors/contains.js.map +1 -1
- package/dist/lib/selectors/endsWith.js +0 -2
- package/dist/lib/selectors/endsWith.js.map +1 -1
- package/dist/lib/selectors/everything.js +0 -2
- package/dist/lib/selectors/everything.js.map +1 -1
- package/dist/lib/selectors/matches.js +0 -2
- package/dist/lib/selectors/matches.js.map +1 -1
- package/dist/lib/selectors/negate.js +2 -4
- package/dist/lib/selectors/negate.js.map +1 -1
- package/dist/lib/selectors/numRange.js +0 -2
- package/dist/lib/selectors/numRange.js.map +1 -1
- package/dist/lib/selectors/startsWith.js +0 -2
- package/dist/lib/selectors/startsWith.js.map +1 -1
- package/dist/lib/sequences/fullSeq.js +5 -3
- package/dist/lib/sequences/fullSeq.js.map +1 -1
- package/dist/lib/slice.js +2 -5
- package/dist/lib/slice.js.map +1 -1
- package/dist/lib/summarize.js +6 -6
- package/dist/lib/summarize.js.map +1 -1
- package/dist/lib/summary/deviation.js +0 -2
- package/dist/lib/summary/deviation.js.map +1 -1
- package/dist/lib/summary/first.js +0 -2
- package/dist/lib/summary/first.js.map +1 -1
- package/dist/lib/summary/last.js +0 -2
- package/dist/lib/summary/last.js.map +1 -1
- package/dist/lib/summary/max.js +0 -2
- package/dist/lib/summary/max.js.map +1 -1
- package/dist/lib/summary/mean.js +0 -2
- package/dist/lib/summary/mean.js.map +1 -1
- package/dist/lib/summary/meanRate.js +0 -2
- package/dist/lib/summary/meanRate.js.map +1 -1
- package/dist/lib/summary/median.js +0 -2
- package/dist/lib/summary/median.js.map +1 -1
- package/dist/lib/summary/min.js +0 -2
- package/dist/lib/summary/min.js.map +1 -1
- package/dist/lib/summary/n.js +0 -2
- package/dist/lib/summary/n.js.map +1 -1
- package/dist/lib/summary/nDistinct.js +2 -4
- package/dist/lib/summary/nDistinct.js.map +1 -1
- package/dist/lib/summary/sum.js +0 -2
- package/dist/lib/summary/sum.js.map +1 -1
- package/dist/lib/summary/variance.js +0 -2
- package/dist/lib/summary/variance.js.map +1 -1
- package/dist/lib/tally.js +4 -4
- package/dist/lib/tally.js.map +1 -1
- package/dist/lib/tidy.js +0 -2
- package/dist/lib/tidy.js.map +1 -1
- package/dist/lib/total.js +0 -2
- package/dist/lib/total.js.map +1 -1
- package/dist/lib/transmute.js +0 -2
- package/dist/lib/transmute.js.map +1 -1
- package/dist/lib/vector/cumsum.js +0 -2
- package/dist/lib/vector/cumsum.js.map +1 -1
- package/dist/lib/vector/lag.js +1 -3
- package/dist/lib/vector/lag.js.map +1 -1
- package/dist/lib/vector/lead.js +1 -3
- package/dist/lib/vector/lead.js.map +1 -1
- package/dist/lib/vector/roll.js +1 -3
- package/dist/lib/vector/roll.js.map +1 -1
- package/dist/lib/vector/rowNumber.js +0 -2
- package/dist/lib/vector/rowNumber.js.map +1 -1
- package/dist/lib/when.js +1 -4
- package/dist/lib/when.js.map +1 -1
- package/dist/tidy.d.ts +217 -1775
- package/dist/umd/tidy.js +307 -184
- package/dist/umd/tidy.js.map +1 -1
- package/dist/umd/tidy.min.js +1 -1
- package/dist/umd/tidy.min.js.map +1 -1
- package/genai-docs/api-core.md +357 -0
- package/genai-docs/api-grouping.md +400 -0
- package/genai-docs/api-joins.md +118 -0
- package/genai-docs/api-other.md +238 -0
- package/genai-docs/api-pivot.md +112 -0
- package/genai-docs/api-selectors.md +159 -0
- package/genai-docs/api-sequences.md +127 -0
- package/genai-docs/api-slice.md +137 -0
- package/genai-docs/api-summarize.md +528 -0
- package/genai-docs/api-vector.md +239 -0
- package/genai-docs/gotchas.md +193 -0
- package/genai-docs/index.md +44 -0
- package/genai-docs/mental-model.md +270 -0
- package/genai-docs/patterns.md +384 -0
- package/genai-docs/quick-reference.md +125 -0
- package/package.json +16 -10
- package/LICENSE +0 -21
package/dist/es/addRows.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"addRows.js","sources":["../../src/addRows.ts"],"sourcesContent":["import { SingleOrArray, singleOrArray } from './helpers/singleOrArray';\nimport { TidyFn } from './types';\n\n/**\n * adds items to the end of the collection\n * @param itemsToAdd The rows/items to be appended to end of collection\n */\nexport function addRows<T extends object>(\n itemsToAdd: SingleOrArray<T> | ((items: T[]) => SingleOrArray<T>)\n): TidyFn<T> {\n const _addRows: TidyFn<T> = (items: T[]): T[] => {\n // TODO: allow options for specifying where it is inserted?\n if (typeof itemsToAdd === 'function') {\n return [...items, ...singleOrArray((itemsToAdd as Function)(items))];\n }\n\n return [...items, ...singleOrArray(itemsToAdd)];\n };\n\n return _addRows;\n}\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"addRows.js","sources":["../../src/addRows.ts"],"sourcesContent":["import { SingleOrArray, singleOrArray } from './helpers/singleOrArray';\nimport { TidyFn } from './types';\n\n/**\n * adds items to the end of the collection\n * @param itemsToAdd The rows/items to be appended to end of collection\n */\nexport function addRows<T extends object>(\n itemsToAdd: SingleOrArray<T> | ((items: T[]) => SingleOrArray<T>)\n): TidyFn<T> {\n const _addRows: TidyFn<T> = (items: T[]): T[] => {\n // TODO: allow options for specifying where it is inserted?\n if (typeof itemsToAdd === 'function') {\n return [...items, ...singleOrArray((itemsToAdd as Function)(items))];\n }\n\n return [...items, ...singleOrArray(itemsToAdd)];\n };\n\n return _addRows;\n}\n"],"names":[],"mappings":";;AAOO,SAAS,QACd,UACW,EAAA;AACX,EAAM,MAAA,QAAA,GAAsB,CAAC,KAAoB,KAAA;AAE/C,IAAI,IAAA,OAAO,eAAe,UAAY,EAAA;AACpC,MAAO,OAAA,CAAC,GAAG,KAAO,EAAA,GAAG,cAAe,UAAwB,CAAA,KAAK,CAAC,CAAC,CAAA,CAAA;AAAA,KACrE;AAEA,IAAA,OAAO,CAAC,GAAG,KAAA,EAAO,GAAG,aAAA,CAAc,UAAU,CAAC,CAAA,CAAA;AAAA,GAChD,CAAA;AAEA,EAAO,OAAA,QAAA,CAAA;AACT;;;;"}
|
package/dist/es/arrange.js
CHANGED
|
@@ -3,12 +3,16 @@ import { singleOrArray } from './helpers/singleOrArray.js';
|
|
|
3
3
|
|
|
4
4
|
function arrange(comparators) {
|
|
5
5
|
const _arrange = (items) => {
|
|
6
|
-
const comparatorFns = singleOrArray(comparators).map(
|
|
6
|
+
const comparatorFns = singleOrArray(comparators).map(
|
|
7
|
+
(comp) => typeof comp === "function" ? (
|
|
8
|
+
// length === 1 means it is an accessor (1 argument). convert to comparator via asc
|
|
9
|
+
comp.length === 1 ? asc(comp) : comp
|
|
10
|
+
) : asc(comp)
|
|
11
|
+
);
|
|
7
12
|
return items.slice().sort((a, b) => {
|
|
8
13
|
for (const comparator of comparatorFns) {
|
|
9
14
|
const result = comparator(a, b);
|
|
10
|
-
if (result)
|
|
11
|
-
return result;
|
|
15
|
+
if (result) return result;
|
|
12
16
|
}
|
|
13
17
|
return 0;
|
|
14
18
|
});
|
|
@@ -28,9 +32,9 @@ function desc(key) {
|
|
|
28
32
|
};
|
|
29
33
|
}
|
|
30
34
|
function fixedOrder(key, order, options) {
|
|
31
|
-
let {position = "start"} = options != null ? options : {};
|
|
35
|
+
let { position = "start" } = options != null ? options : {};
|
|
32
36
|
const positionFactor = position === "end" ? -1 : 1;
|
|
33
|
-
const indexMap = new Map();
|
|
37
|
+
const indexMap = /* @__PURE__ */ new Map();
|
|
34
38
|
for (let i = 0; i < order.length; ++i) {
|
|
35
39
|
indexMap.set(order[i], i);
|
|
36
40
|
}
|
package/dist/es/arrange.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"arrange.js","sources":["../../src/arrange.ts"],"sourcesContent":["import { ascending } from 'd3-array';\nimport { SingleOrArray, singleOrArray } from './helpers/singleOrArray';\nimport { Comparator, Key, KeyOrFn, TidyFn } from './types';\n\n/**\n * Sorts items\n * @param comparators Given a, b return -1 if a comes before b, 0 if equal, 1 if after\n */\nexport function arrange<T extends object>(\n // note: had to switch to returning `any` instead of using Comparator<T> (returns number)\n // for #49 - otherwise typescript failed to do type inference on accessors\n comparators: SingleOrArray<Key | ((a: T, b: T) => any)>\n): TidyFn<T> {\n const _arrange: TidyFn<T> = (items: T[]): T[] => {\n // expand strings `key` to `asc(key)`\n const comparatorFns = singleOrArray(comparators).map((comp) =>\n typeof comp === 'function'\n ? // length === 1 means it is an accessor (1 argument). convert to comparator via asc\n comp.length === 1\n ? asc(comp as (d: T) => unknown)\n : (comp as Comparator<T>)\n : asc<T>(comp)\n );\n\n return items.slice().sort((a, b) => {\n for (const comparator of comparatorFns) {\n const result = comparator(a, b);\n if (result) return result;\n }\n\n return 0;\n });\n };\n\n return _arrange;\n}\n\n/**\n * Creates an ascending comparator based on a key\n * @param key property key of T\n */\nexport function asc<T>(key: Key | ((d: T) => any)): Comparator<T> {\n const keyFn = typeof key === 'function' ? key : (d: any) => d[key];\n\n return function _asc(a: T, b: T) {\n return emptyAwareComparator(keyFn(a), keyFn(b), false);\n };\n}\n\n/**\n * Creates a descending comparator based on a key\n * @param key property key of T\n */\nexport function desc<T>(key: Key | ((d: T) => any)): Comparator<T> {\n const keyFn = typeof key === 'function' ? key : (d: any) => d[key];\n return function _desc(a: T, b: T) {\n return emptyAwareComparator(keyFn(a), keyFn(b), true);\n };\n}\n\n/**\n * Creates a comparator that sorts values based on a key\n * and a supplied array of the desired order for the values.\n * Items not found in the array will be sorted last.\n * @param order array of desired sort order\n */\nexport function fixedOrder<T>(\n key: KeyOrFn<T>,\n order: Array<T[keyof T]>,\n options?: { position?: 'start' | 'end' }\n): (a: T, b: T) => number {\n let { position = 'start' } = options ?? {};\n const positionFactor = position === 'end' ? -1 : 1;\n\n const indexMap = new Map();\n for (let i = 0; i < order.length; ++i) {\n indexMap.set(order[i], i);\n }\n\n const keyFn =\n typeof key === 'function'\n ? key\n : (d: T) =>
|
|
1
|
+
{"version":3,"file":"arrange.js","sources":["../../src/arrange.ts"],"sourcesContent":["import { ascending } from 'd3-array';\nimport { SingleOrArray, singleOrArray } from './helpers/singleOrArray';\nimport { Comparator, Key, KeyOrFn, TidyFn } from './types';\n\n/**\n * Sorts items\n * @param comparators Given a, b return -1 if a comes before b, 0 if equal, 1 if after\n */\nexport function arrange<T extends object>(\n // note: had to switch to returning `any` instead of using Comparator<T> (returns number)\n // for #49 - otherwise typescript failed to do type inference on accessors\n comparators: SingleOrArray<Key | ((a: T, b: T) => any)>\n): TidyFn<T> {\n const _arrange: TidyFn<T> = (items: T[]): T[] => {\n // expand strings `key` to `asc(key)`\n const comparatorFns = singleOrArray(comparators).map((comp) =>\n typeof comp === 'function'\n ? // length === 1 means it is an accessor (1 argument). convert to comparator via asc\n comp.length === 1\n ? asc(comp as (d: T) => unknown)\n : (comp as Comparator<T>)\n : asc<T>(comp)\n );\n\n return items.slice().sort((a, b) => {\n for (const comparator of comparatorFns) {\n const result = comparator(a, b);\n if (result) return result;\n }\n\n return 0;\n });\n };\n\n return _arrange;\n}\n\n/**\n * Creates an ascending comparator based on a key\n * @param key property key of T\n */\nexport function asc<T>(key: Key | ((d: T) => any)): Comparator<T> {\n const keyFn = typeof key === 'function' ? key : (d: any) => d[key];\n\n return function _asc(a: T, b: T) {\n return emptyAwareComparator(keyFn(a), keyFn(b), false);\n };\n}\n\n/**\n * Creates a descending comparator based on a key\n * @param key property key of T\n */\nexport function desc<T>(key: Key | ((d: T) => any)): Comparator<T> {\n const keyFn = typeof key === 'function' ? key : (d: any) => d[key];\n return function _desc(a: T, b: T) {\n return emptyAwareComparator(keyFn(a), keyFn(b), true);\n };\n}\n\n/**\n * Creates a comparator that sorts values based on a key\n * and a supplied array of the desired order for the values.\n * Items not found in the array will be sorted last.\n * @param order array of desired sort order\n */\nexport function fixedOrder<T>(\n key: KeyOrFn<T>,\n order: Array<T[keyof T]>,\n options?: { position?: 'start' | 'end' }\n): (a: T, b: T) => number {\n let { position = 'start' } = options ?? {};\n const positionFactor = position === 'end' ? -1 : 1;\n\n const indexMap = new Map();\n for (let i = 0; i < order.length; ++i) {\n indexMap.set(order[i], i);\n }\n\n const keyFn =\n typeof key === 'function'\n ? key\n : (d: T) => d[key as keyof T] as unknown as any;\n\n return function _fixedOrder(a: T, b: T) {\n const aIndex: number = indexMap.get(keyFn(a)) ?? -1;\n const bIndex: number = indexMap.get(keyFn(b)) ?? -1;\n\n if (aIndex >= 0 && bIndex >= 0) {\n return aIndex - bIndex;\n }\n\n if (aIndex >= 0) {\n return positionFactor * -1;\n }\n\n if (bIndex >= 0) {\n return positionFactor * 1;\n }\n\n return 0;\n };\n}\n\nfunction emptyAwareComparator(aInput: any, bInput: any, desc: boolean) {\n // we swap order to get descending behavior\n let a = desc ? bInput : aInput;\n let b = desc ? aInput : bInput;\n\n // NaN, null, undefined is the order for emptys\n if (isEmpty(a) && isEmpty(b)) {\n const rankA = a !== a ? 0 : a === null ? 1 : 2;\n const rankB = b !== b ? 0 : b === null ? 1 : 2;\n const order = rankA - rankB;\n return desc ? -order : order;\n }\n\n // keep empty values at the bottom\n if (isEmpty(a)) {\n return desc ? -1 : 1;\n }\n if (isEmpty(b)) {\n return desc ? 1 : -1;\n }\n\n // descending is handled by swapping the a and b args at the start\n return ascending(a, b);\n}\n\nfunction isEmpty(value: any) {\n return value == null || value !== value /* NaN check */;\n}\n"],"names":["desc"],"mappings":"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"}
|
package/dist/es/complete.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"complete.js","sources":["../../src/complete.ts"],"sourcesContent":["import { expand, KeyMap } from './expand';\nimport { leftJoin } from './leftJoin';\nimport { Key, TidyFn } from './types';\nimport { replaceNully } from './replaceNully';\nimport { SingleOrArray } from './helpers/singleOrArray';\n\n/**\n * Complete a collection with missing combinations of data\n * @param expandKeys The keys to expand to all combinations of\n * @param replaceNullySpec a map from key name to value of how to deal with undefined values\n */\nexport function complete<T extends object>(\n expandKeys: SingleOrArray<Key> | KeyMap<T>,\n replaceNullySpec?: Partial<T> | null | undefined\n): TidyFn<T> {\n const _complete: TidyFn<T> = (items: T[]): T[] => {\n const expanded = expand<T, any>(expandKeys)(items);\n const joined = leftJoin(items)(expanded) as T[]; // actually may have some undefineds...\n return replaceNullySpec\n ? (replaceNully(replaceNullySpec)(joined) as T[])\n : joined;\n };\n\n return _complete;\n}\n"],"names":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"complete.js","sources":["../../src/complete.ts"],"sourcesContent":["import { expand, KeyMap } from './expand';\nimport { leftJoin } from './leftJoin';\nimport { Key, TidyFn } from './types';\nimport { replaceNully } from './replaceNully';\nimport { SingleOrArray } from './helpers/singleOrArray';\n\n/**\n * Complete a collection with missing combinations of data\n * @param expandKeys The keys to expand to all combinations of\n * @param replaceNullySpec a map from key name to value of how to deal with undefined values\n */\nexport function complete<T extends object>(\n expandKeys: SingleOrArray<Key> | KeyMap<T>,\n replaceNullySpec?: Partial<T> | null | undefined\n): TidyFn<T> {\n const _complete: TidyFn<T> = (items: T[]): T[] => {\n const expanded = expand<T, any>(expandKeys)(items);\n const joined = leftJoin(items)(expanded) as T[]; // actually may have some undefineds...\n return replaceNullySpec\n ? (replaceNully(replaceNullySpec)(joined) as T[])\n : joined;\n };\n\n return _complete;\n}\n"],"names":[],"mappings":";;;;AAWgB,SAAA,QAAA,CACd,YACA,gBACW,EAAA;AACX,EAAM,MAAA,SAAA,GAAuB,CAAC,KAAoB,KAAA;AAChD,IAAA,MAAM,QAAW,GAAA,MAAA,CAAe,UAAU,CAAA,CAAE,KAAK,CAAA,CAAA;AACjD,IAAA,MAAM,MAAS,GAAA,QAAA,CAAS,KAAK,CAAA,CAAE,QAAQ,CAAA,CAAA;AACvC,IAAA,OAAO,gBACF,GAAA,YAAA,CAAa,gBAAgB,CAAA,CAAE,MAAM,CACtC,GAAA,MAAA,CAAA;AAAA,GACN,CAAA;AAEA,EAAO,OAAA,SAAA,CAAA;AACT;;;;"}
|
package/dist/es/count.js
CHANGED
|
@@ -7,8 +7,12 @@ import { tidy } from './tidy.js';
|
|
|
7
7
|
function count(groupKeys, options) {
|
|
8
8
|
const _count = (items) => {
|
|
9
9
|
options = options != null ? options : {};
|
|
10
|
-
const {name = "n", sort} = options;
|
|
11
|
-
const results = tidy(
|
|
10
|
+
const { name = "n", sort } = options;
|
|
11
|
+
const results = tidy(
|
|
12
|
+
items,
|
|
13
|
+
groupBy(groupKeys, [tally(options)]),
|
|
14
|
+
sort ? arrange(desc(name)) : identity
|
|
15
|
+
);
|
|
12
16
|
return results;
|
|
13
17
|
};
|
|
14
18
|
return _count;
|
package/dist/es/count.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"count.js","sources":["../../src/count.ts"],"sourcesContent":["import { arrange, desc } from './arrange';\nimport { groupBy } from './groupBy';\nimport { identity } from './helpers/identity';\nimport { SingleOrArray } from './helpers/singleOrArray';\nimport { tally } from './tally';\nimport { tidy } from './tidy';\nimport { KeyOrFn } from './types';\n\ntype CountOptions = {\n name?: string;\n sort?: boolean;\n wt?: string;\n};\n\n/**\n * Tallies the number distinct values for the specified keys and adds\n * the count as a new key (default `n`). Optionally sorts by the count.\n */\nexport function count<T extends object, Keys extends SingleOrArray<KeyOrFn<T>>>(\n groupKeys: Keys,\n options?: CountOptions | null | undefined\n) {\n const _count = (items: T[]) => {\n options = options ?? {};\n const { name = 'n', sort } = options;\n\n const results = tidy(\n items,\n groupBy(groupKeys, [tally(options)]),\n sort ? arrange(desc(name)) : identity\n );\n\n return results;\n };\n\n return _count;\n}\n"],"names":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"count.js","sources":["../../src/count.ts"],"sourcesContent":["import { arrange, desc } from './arrange';\nimport { groupBy } from './groupBy';\nimport { identity } from './helpers/identity';\nimport { SingleOrArray } from './helpers/singleOrArray';\nimport { tally } from './tally';\nimport { tidy } from './tidy';\nimport { KeyOrFn } from './types';\n\ntype CountOptions = {\n name?: string;\n sort?: boolean;\n wt?: string;\n};\n\n/**\n * Tallies the number distinct values for the specified keys and adds\n * the count as a new key (default `n`). Optionally sorts by the count.\n */\nexport function count<T extends object, Keys extends SingleOrArray<KeyOrFn<T>>>(\n groupKeys: Keys,\n options?: CountOptions | null | undefined\n) {\n const _count = (items: T[]) => {\n options = options ?? {};\n const { name = 'n', sort } = options;\n\n const results = tidy(\n items,\n groupBy(groupKeys, [tally(options)]),\n sort ? arrange(desc(name)) : identity\n );\n\n return results;\n };\n\n return _count;\n}\n"],"names":[],"mappings":";;;;;;AAkBgB,SAAA,KAAA,CACd,WACA,OACA,EAAA;AACA,EAAM,MAAA,MAAA,GAAS,CAAC,KAAe,KAAA;AAC7B,IAAA,OAAA,GAAU,4BAAW,EAAC,CAAA;AACtB,IAAA,MAAM,EAAE,IAAA,GAAO,GAAK,EAAA,IAAA,EAAS,GAAA,OAAA,CAAA;AAE7B,IAAA,MAAM,OAAU,GAAA,IAAA;AAAA,MACd,KAAA;AAAA,MACA,QAAQ,SAAW,EAAA,CAAC,KAAM,CAAA,OAAO,CAAC,CAAC,CAAA;AAAA,MACnC,IAAO,GAAA,OAAA,CAAQ,IAAK,CAAA,IAAI,CAAC,CAAI,GAAA,QAAA;AAAA,KAC/B,CAAA;AAEA,IAAO,OAAA,OAAA,CAAA;AAAA,GACT,CAAA;AAEA,EAAO,OAAA,MAAA,CAAA;AACT;;;;"}
|
package/dist/es/debug.js
CHANGED
|
@@ -10,13 +10,15 @@ function debug(label, options) {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
options = options != null ? options : {};
|
|
13
|
-
const {limit = 10, output = "table"} = options;
|
|
13
|
+
const { limit = 10, output = "table" } = options;
|
|
14
14
|
const dashString = "--------------------------------------------------------------------------------";
|
|
15
15
|
let numDashes = dashString.length;
|
|
16
16
|
const prefixedLabel = prefix + "]" + (label == null ? "" : " " + label);
|
|
17
17
|
numDashes = Math.max(0, numDashes - (prefixedLabel.length + 2));
|
|
18
18
|
console.log(`${prefixedLabel} ${dashString.substring(0, numDashes)}`);
|
|
19
|
-
console[output](
|
|
19
|
+
console[output](
|
|
20
|
+
limit == null || limit >= items.length ? items : items.slice(0, limit)
|
|
21
|
+
);
|
|
20
22
|
return items;
|
|
21
23
|
};
|
|
22
24
|
return _debug;
|
package/dist/es/debug.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debug.js","sources":["../../src/debug.ts"],"sourcesContent":["import { TidyContext, TidyFn } from './types';\n\ntype Options = {\n limit?: number | null;\n output?: 'log' | 'table';\n};\n\n/**\n * Debugs items\n */\nexport function debug<T extends object>(\n label?: string | null | undefined,\n options?: Options | null | undefined\n): TidyFn<T> {\n const _debug: TidyFn<T> = (items: T[], context?: TidyContext): T[] => {\n let prefix = '[tidy.debug';\n if (context?.groupKeys?.length) {\n const groupKeys = context.groupKeys;\n const groupKeyStrings = groupKeys\n .map((keyPair: any) => keyPair.join(': '))\n .join(', ');\n if (groupKeyStrings.length) {\n prefix += '|' + groupKeyStrings;\n }\n }\n options = options ?? {};\n const { limit = 10, output = 'table' } = options;\n\n // check for sneaky group keys as last arg\n const dashString =\n '--------------------------------------------------------------------------------';\n let numDashes = dashString.length;\n const prefixedLabel = prefix + ']' + (label == null ? '' : ' ' + label);\n numDashes = Math.max(0, numDashes - (prefixedLabel.length + 2));\n\n console.log(`${prefixedLabel} ${dashString.substring(0, numDashes)}`);\n console[output](\n limit == null || limit >= items.length ? items : items.slice(0, limit)\n );\n return items;\n };\n\n return _debug;\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"debug.js","sources":["../../src/debug.ts"],"sourcesContent":["import { TidyContext, TidyFn } from './types';\n\ntype Options = {\n limit?: number | null;\n output?: 'log' | 'table';\n};\n\n/**\n * Debugs items\n */\nexport function debug<T extends object>(\n label?: string | null | undefined,\n options?: Options | null | undefined\n): TidyFn<T> {\n const _debug: TidyFn<T> = (items: T[], context?: TidyContext): T[] => {\n let prefix = '[tidy.debug';\n if (context?.groupKeys?.length) {\n const groupKeys = context.groupKeys;\n const groupKeyStrings = groupKeys\n .map((keyPair: any) => keyPair.join(': '))\n .join(', ');\n if (groupKeyStrings.length) {\n prefix += '|' + groupKeyStrings;\n }\n }\n options = options ?? {};\n const { limit = 10, output = 'table' } = options;\n\n // check for sneaky group keys as last arg\n const dashString =\n '--------------------------------------------------------------------------------';\n let numDashes = dashString.length;\n const prefixedLabel = prefix + ']' + (label == null ? '' : ' ' + label);\n numDashes = Math.max(0, numDashes - (prefixedLabel.length + 2));\n\n console.log(`${prefixedLabel} ${dashString.substring(0, numDashes)}`);\n console[output](\n limit == null || limit >= items.length ? items : items.slice(0, limit)\n );\n return items;\n };\n\n return _debug;\n}\n"],"names":[],"mappings":"AAUgB,SAAA,KAAA,CACd,OACA,OACW,EAAA;AACX,EAAM,MAAA,MAAA,GAAoB,CAAC,KAAA,EAAY,OAA+B,KAAA;AAdxE,IAAA,IAAA,EAAA,CAAA;AAeI,IAAA,IAAI,MAAS,GAAA,aAAA,CAAA;AACb,IAAI,IAAA,CAAA,EAAA,GAAA,OAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,OAAA,CAAS,SAAT,KAAA,IAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAoB,MAAQ,EAAA;AAC9B,MAAA,MAAM,YAAY,OAAQ,CAAA,SAAA,CAAA;AAC1B,MAAM,MAAA,eAAA,GAAkB,SACrB,CAAA,GAAA,CAAI,CAAC,OAAA,KAAiB,OAAQ,CAAA,IAAA,CAAK,IAAI,CAAC,CACxC,CAAA,IAAA,CAAK,IAAI,CAAA,CAAA;AACZ,MAAA,IAAI,gBAAgB,MAAQ,EAAA;AAC1B,QAAA,MAAA,IAAU,GAAM,GAAA,eAAA,CAAA;AAAA,OAClB;AAAA,KACF;AACA,IAAA,OAAA,GAAU,4BAAW,EAAC,CAAA;AACtB,IAAA,MAAM,EAAE,KAAA,GAAQ,EAAI,EAAA,MAAA,GAAS,SAAY,GAAA,OAAA,CAAA;AAGzC,IAAA,MAAM,UACJ,GAAA,kFAAA,CAAA;AACF,IAAA,IAAI,YAAY,UAAW,CAAA,MAAA,CAAA;AAC3B,IAAA,MAAM,gBAAgB,MAAS,GAAA,GAAA,IAAO,KAAS,IAAA,IAAA,GAAO,KAAK,GAAM,GAAA,KAAA,CAAA,CAAA;AACjE,IAAA,SAAA,GAAY,KAAK,GAAI,CAAA,CAAA,EAAG,SAAa,IAAA,aAAA,CAAc,SAAS,CAAE,CAAA,CAAA,CAAA;AAE9D,IAAQ,OAAA,CAAA,GAAA,CAAI,GAAG,aAAa,CAAA,CAAA,EAAI,WAAW,SAAU,CAAA,CAAA,EAAG,SAAS,CAAC,CAAE,CAAA,CAAA,CAAA;AACpE,IAAA,OAAA,CAAQ,MAAM,CAAA;AAAA,MACZ,KAAA,IAAS,QAAQ,KAAS,IAAA,KAAA,CAAM,SAAS,KAAQ,GAAA,KAAA,CAAM,KAAM,CAAA,CAAA,EAAG,KAAK,CAAA;AAAA,KACvE,CAAA;AACA,IAAO,OAAA,KAAA,CAAA;AAAA,GACT,CAAA;AAEA,EAAO,OAAA,MAAA,CAAA;AACT;;;;"}
|
package/dist/es/distinct.js
CHANGED
|
@@ -4,13 +4,13 @@ function distinct(keys) {
|
|
|
4
4
|
const _distinct = (items) => {
|
|
5
5
|
keys = singleOrArray(keys);
|
|
6
6
|
if (!keys.length) {
|
|
7
|
-
const set = new Set();
|
|
7
|
+
const set = /* @__PURE__ */ new Set();
|
|
8
8
|
for (const item of items) {
|
|
9
9
|
set.add(item);
|
|
10
10
|
}
|
|
11
11
|
return Array.from(set);
|
|
12
12
|
}
|
|
13
|
-
const rootMap = new Map();
|
|
13
|
+
const rootMap = /* @__PURE__ */ new Map();
|
|
14
14
|
const distinctItems = [];
|
|
15
15
|
const lastKey = keys[keys.length - 1];
|
|
16
16
|
for (const item of items) {
|
|
@@ -27,7 +27,7 @@ function distinct(keys) {
|
|
|
27
27
|
break;
|
|
28
28
|
}
|
|
29
29
|
if (!map.has(mapItemKey)) {
|
|
30
|
-
map.set(mapItemKey, new Map());
|
|
30
|
+
map.set(mapItemKey, /* @__PURE__ */ new Map());
|
|
31
31
|
}
|
|
32
32
|
map = map.get(mapItemKey);
|
|
33
33
|
}
|
package/dist/es/distinct.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"distinct.js","sources":["../../src/distinct.ts"],"sourcesContent":["import { KeyOrFn, TidyFn } from './types';\nimport { SingleOrArray, singleOrArray } from './helpers/singleOrArray';\n\n/**\n * Removes items with duplicate values for the specified keys.\n * If no keys provided, uses strict equality.\n *\n * @param keys Keys to compute distinct across\n */\nexport function distinct<T extends object>(\n keys?: SingleOrArray<KeyOrFn<T>> | null | undefined\n): TidyFn<T> {\n const _distinct: TidyFn<T> = (items: T[]): T[] => {\n keys = singleOrArray(keys);\n\n if (!keys.length) {\n // https://jsperf.com/unique-array-by-strict-equality\n const set = new Set<T>();\n for (const item of items) {\n set.add(item);\n }\n return Array.from(set);\n }\n\n // compare keys\n // https://jsperf.com/distinct-by-key\n // turns out nested Maps are faster than string keys. AND they support\n // and arbitrary value.\n const rootMap = new Map();\n const distinctItems: T[] = [];\n const lastKey = keys[keys.length - 1];\n for (const item of items) {\n let map = rootMap;\n let hasItem = false;\n\n // go through each key to find out if we have it\n for (const key of keys) {\n const mapItemKey =\n typeof key === 'function' ? key(item) : item[key as keyof T];\n // last key, check if we already added it\n if (key === lastKey) {\n hasItem = map.has(mapItemKey);\n if (!hasItem) {\n distinctItems.push(item);\n map.set(mapItemKey, true);\n }\n break;\n }\n\n // create maps all the way down\n if (!map.has(mapItemKey)) {\n map.set(mapItemKey, new Map());\n }\n\n // move to next inner map\n map = map.get(mapItemKey);\n }\n }\n\n return distinctItems;\n };\n\n return _distinct;\n}\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"distinct.js","sources":["../../src/distinct.ts"],"sourcesContent":["import { KeyOrFn, TidyFn } from './types';\nimport { SingleOrArray, singleOrArray } from './helpers/singleOrArray';\n\n/**\n * Removes items with duplicate values for the specified keys.\n * If no keys provided, uses strict equality.\n *\n * @param keys Keys to compute distinct across\n */\nexport function distinct<T extends object>(\n keys?: SingleOrArray<KeyOrFn<T>> | null | undefined\n): TidyFn<T> {\n const _distinct: TidyFn<T> = (items: T[]): T[] => {\n keys = singleOrArray(keys);\n\n if (!keys.length) {\n // https://jsperf.com/unique-array-by-strict-equality\n const set = new Set<T>();\n for (const item of items) {\n set.add(item);\n }\n return Array.from(set);\n }\n\n // compare keys\n // https://jsperf.com/distinct-by-key\n // turns out nested Maps are faster than string keys. AND they support\n // and arbitrary value.\n const rootMap = new Map();\n const distinctItems: T[] = [];\n const lastKey = keys[keys.length - 1];\n for (const item of items) {\n let map = rootMap;\n let hasItem = false;\n\n // go through each key to find out if we have it\n for (const key of keys) {\n const mapItemKey =\n typeof key === 'function' ? key(item) : item[key as keyof T];\n // last key, check if we already added it\n if (key === lastKey) {\n hasItem = map.has(mapItemKey);\n if (!hasItem) {\n distinctItems.push(item);\n map.set(mapItemKey, true);\n }\n break;\n }\n\n // create maps all the way down\n if (!map.has(mapItemKey)) {\n map.set(mapItemKey, new Map());\n }\n\n // move to next inner map\n map = map.get(mapItemKey);\n }\n }\n\n return distinctItems;\n };\n\n return _distinct;\n}\n"],"names":[],"mappings":";;AASO,SAAS,SACd,IACW,EAAA;AACX,EAAM,MAAA,SAAA,GAAuB,CAAC,KAAoB,KAAA;AAChD,IAAA,IAAA,GAAO,cAAc,IAAI,CAAA,CAAA;AAEzB,IAAI,IAAA,CAAC,KAAK,MAAQ,EAAA;AAEhB,MAAM,MAAA,GAAA,uBAAU,GAAO,EAAA,CAAA;AACvB,MAAA,KAAA,MAAW,QAAQ,KAAO,EAAA;AACxB,QAAA,GAAA,CAAI,IAAI,IAAI,CAAA,CAAA;AAAA,OACd;AACA,MAAO,OAAA,KAAA,CAAM,KAAK,GAAG,CAAA,CAAA;AAAA,KACvB;AAMA,IAAM,MAAA,OAAA,uBAAc,GAAI,EAAA,CAAA;AACxB,IAAA,MAAM,gBAAqB,EAAC,CAAA;AAC5B,IAAA,MAAM,OAAU,GAAA,IAAA,CAAK,IAAK,CAAA,MAAA,GAAS,CAAC,CAAA,CAAA;AACpC,IAAA,KAAA,MAAW,QAAQ,KAAO,EAAA;AACxB,MAAA,IAAI,GAAM,GAAA,OAAA,CAAA;AACV,MAAA,IAAI,OAAU,GAAA,KAAA,CAAA;AAGd,MAAA,KAAA,MAAW,OAAO,IAAM,EAAA;AACtB,QAAM,MAAA,UAAA,GACJ,OAAO,GAAQ,KAAA,UAAA,GAAa,IAAI,IAAI,CAAA,GAAI,KAAK,GAAc,CAAA,CAAA;AAE7D,QAAA,IAAI,QAAQ,OAAS,EAAA;AACnB,UAAU,OAAA,GAAA,GAAA,CAAI,IAAI,UAAU,CAAA,CAAA;AAC5B,UAAA,IAAI,CAAC,OAAS,EAAA;AACZ,YAAA,aAAA,CAAc,KAAK,IAAI,CAAA,CAAA;AACvB,YAAI,GAAA,CAAA,GAAA,CAAI,YAAY,IAAI,CAAA,CAAA;AAAA,WAC1B;AACA,UAAA,MAAA;AAAA,SACF;AAGA,QAAA,IAAI,CAAC,GAAA,CAAI,GAAI,CAAA,UAAU,CAAG,EAAA;AACxB,UAAA,GAAA,CAAI,GAAI,CAAA,UAAA,kBAAgB,IAAA,GAAA,EAAK,CAAA,CAAA;AAAA,SAC/B;AAGA,QAAM,GAAA,GAAA,GAAA,CAAI,IAAI,UAAU,CAAA,CAAA;AAAA,OAC1B;AAAA,KACF;AAEA,IAAO,OAAA,aAAA,CAAA;AAAA,GACT,CAAA;AAEA,EAAO,OAAA,SAAA,CAAA;AACT;;;;"}
|
package/dist/es/expand.js
CHANGED
|
@@ -12,26 +12,31 @@ function expand(expandKeys) {
|
|
|
12
12
|
} else {
|
|
13
13
|
values = Array.from(new Set(items.map((d) => d[key])));
|
|
14
14
|
}
|
|
15
|
-
vectors.push(values.map((value) => ({[key]: value})));
|
|
15
|
+
vectors.push(values.map((value) => ({ [key]: value })));
|
|
16
16
|
}
|
|
17
17
|
return makeCombinations(vectors);
|
|
18
18
|
};
|
|
19
19
|
return _expand;
|
|
20
20
|
}
|
|
21
|
+
const EXPAND_WARN_THRESHOLD = 1e5;
|
|
21
22
|
function makeCombinations(vectors) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
if (!vectors.length) return [];
|
|
24
|
+
const totalSize = vectors.reduce((acc, v) => acc * v.length, 1);
|
|
25
|
+
if (totalSize > EXPAND_WARN_THRESHOLD) {
|
|
26
|
+
console.warn(
|
|
27
|
+
`tidy expand: generating ${totalSize.toLocaleString()} combinations. This may be slow or use excessive memory.`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
let result = [null];
|
|
31
|
+
for (const vector of vectors) {
|
|
32
|
+
const next = [];
|
|
33
|
+
for (const baseObj of result) {
|
|
34
|
+
for (const item of vector) {
|
|
35
|
+
next.push(baseObj == null ? item : { ...baseObj, ...item });
|
|
36
|
+
}
|
|
31
37
|
}
|
|
38
|
+
result = next;
|
|
32
39
|
}
|
|
33
|
-
const result = [];
|
|
34
|
-
combine(result, null, vectors);
|
|
35
40
|
return result;
|
|
36
41
|
}
|
|
37
42
|
function makeKeyMap(keys) {
|
|
@@ -44,7 +49,7 @@ function makeKeyMap(keys) {
|
|
|
44
49
|
} else if (typeof keys === "object") {
|
|
45
50
|
return keys;
|
|
46
51
|
}
|
|
47
|
-
return {[keys]: keys};
|
|
52
|
+
return { [keys]: keys };
|
|
48
53
|
}
|
|
49
54
|
|
|
50
55
|
export { expand, makeKeyMap };
|
package/dist/es/expand.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expand.js","sources":["../../src/expand.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"expand.js","sources":["../../src/expand.ts"],"sourcesContent":["import { SingleOrArray } from './helpers/singleOrArray';\nimport { Key, TidyFn } from './types';\nimport { Prettify } from './type-utils';\n\n// helper types\nexport type KeyMap<T extends object = any> = Partial<{\n [key in keyof T]: keyof T | Array<T[key]> | ((items: T[]) => T[key][]);\n}>;\n\n/**\n * Expands a set of items to include all combinations of the specified keys.\n */\n// prettier-ignore\nexport function expand<T extends object = any, K extends keyof T = keyof T>(expandKeys: K): TidyFn<T, Prettify<Pick<T, K>>>;\n// prettier-ignore\nexport function expand<T extends object = any, K extends (keyof T)[] = (keyof T)[]>(expandKeys: K): TidyFn<T, Prettify<Pick<T, K[number]>>>;\n// prettier-ignore\nexport function expand<T extends object = any, K extends KeyMap<T> = KeyMap<T>>(expandKeys: K): TidyFn<T, Pick<T, Extract<keyof K, keyof T>>>\n// prettier-ignore\nexport function expand<T extends object>(expandKeys: SingleOrArray<Key> | KeyMap<T>): TidyFn<T> {\n const _expand: TidyFn<T> = (items: T[]) => {\n const keyMap = makeKeyMap(expandKeys);\n\n // for each key, get all distinct values or use the provided values\n const vectors = [];\n for (const key in keyMap) {\n const keyValue = keyMap[key];\n let values;\n if (typeof keyValue === 'function') {\n values = keyValue(items);\n } else if (Array.isArray(keyValue)) {\n values = keyValue;\n } else {\n // read distinct values from the key in the data\n values = Array.from(new Set(items.map((d) => d[key as keyof T])));\n }\n\n vectors.push(values.map((value: any) => ({ [key]: value })));\n }\n\n // make all combinations of all value sets\n return makeCombinations(vectors);\n };\n\n return _expand;\n}\n\n/*\n Recursively compute key combinations\n*/\nconst EXPAND_WARN_THRESHOLD = 100_000;\n\n/*\n Iteratively compute key combinations (avoids recursive array slicing)\n*/\nfunction makeCombinations(vectors: any[][]): any[] {\n if (!vectors.length) return [];\n\n // warn if Cartesian product will be very large\n const totalSize = vectors.reduce((acc, v) => acc * v.length, 1);\n if (totalSize > EXPAND_WARN_THRESHOLD) {\n console.warn(\n `tidy expand: generating ${totalSize.toLocaleString()} combinations. ` +\n `This may be slow or use excessive memory.`\n );\n }\n\n let result: any[] = [null];\n for (const vector of vectors) {\n const next: any[] = [];\n for (const baseObj of result) {\n for (const item of vector) {\n next.push(baseObj == null ? item : { ...baseObj, ...item });\n }\n }\n result = next;\n }\n return result;\n}\n\n// convert by option in to a map from T key to JoinT key\nexport function makeKeyMap(keys: SingleOrArray<Key> | KeyMap): KeyMap {\n if (Array.isArray(keys)) {\n const keyMap: KeyMap = {};\n for (const key of keys) {\n keyMap[key as any] = key;\n }\n return keyMap;\n } else if (typeof keys === 'object') {\n return keys;\n }\n\n return { [keys]: keys as any } as KeyMap;\n}\n"],"names":[],"mappings":"AAmBO,SAAS,OAAyB,UAAuD,EAAA;AAC9F,EAAM,MAAA,OAAA,GAAqB,CAAC,KAAe,KAAA;AACzC,IAAM,MAAA,MAAA,GAAS,WAAW,UAAU,CAAA,CAAA;AAGpC,IAAA,MAAM,UAAU,EAAC,CAAA;AACjB,IAAA,KAAA,MAAW,OAAO,MAAQ,EAAA;AACxB,MAAM,MAAA,QAAA,GAAW,OAAO,GAAG,CAAA,CAAA;AAC3B,MAAI,IAAA,MAAA,CAAA;AACJ,MAAI,IAAA,OAAO,aAAa,UAAY,EAAA;AAClC,QAAA,MAAA,GAAS,SAAS,KAAK,CAAA,CAAA;AAAA,OACd,MAAA,IAAA,KAAA,CAAM,OAAQ,CAAA,QAAQ,CAAG,EAAA;AAClC,QAAS,MAAA,GAAA,QAAA,CAAA;AAAA,OACJ,MAAA;AAEL,QAAA,MAAA,GAAS,KAAM,CAAA,IAAA,CAAK,IAAI,GAAA,CAAI,KAAM,CAAA,GAAA,CAAI,CAAC,CAAA,KAAM,CAAE,CAAA,GAAc,CAAC,CAAC,CAAC,CAAA,CAAA;AAAA,OAClE;AAEA,MAAQ,OAAA,CAAA,IAAA,CAAK,MAAO,CAAA,GAAA,CAAI,CAAC,KAAA,MAAgB,EAAE,CAAC,GAAG,GAAG,KAAM,EAAA,CAAE,CAAC,CAAA,CAAA;AAAA,KAC7D;AAGA,IAAA,OAAO,iBAAiB,OAAO,CAAA,CAAA;AAAA,GACjC,CAAA;AAEA,EAAO,OAAA,OAAA,CAAA;AACT,CAAA;AAKA,MAAM,qBAAwB,GAAA,GAAA,CAAA;AAK9B,SAAS,iBAAiB,OAAyB,EAAA;AACjD,EAAA,IAAI,CAAC,OAAA,CAAQ,MAAQ,EAAA,OAAO,EAAC,CAAA;AAG7B,EAAM,MAAA,SAAA,GAAY,QAAQ,MAAO,CAAA,CAAC,KAAK,CAAM,KAAA,GAAA,GAAM,CAAE,CAAA,MAAA,EAAQ,CAAC,CAAA,CAAA;AAC9D,EAAA,IAAI,YAAY,qBAAuB,EAAA;AACrC,IAAQ,OAAA,CAAA,IAAA;AAAA,MACN,CAAA,wBAAA,EAA2B,SAAU,CAAA,cAAA,EAAgB,CAAA,wDAAA,CAAA;AAAA,KAEvD,CAAA;AAAA,GACF;AAEA,EAAI,IAAA,MAAA,GAAgB,CAAC,IAAI,CAAA,CAAA;AACzB,EAAA,KAAA,MAAW,UAAU,OAAS,EAAA;AAC5B,IAAA,MAAM,OAAc,EAAC,CAAA;AACrB,IAAA,KAAA,MAAW,WAAW,MAAQ,EAAA;AAC5B,MAAA,KAAA,MAAW,QAAQ,MAAQ,EAAA;AACzB,QAAK,IAAA,CAAA,IAAA,CAAK,WAAW,IAAO,GAAA,IAAA,GAAO,EAAE,GAAG,OAAA,EAAS,GAAG,IAAA,EAAM,CAAA,CAAA;AAAA,OAC5D;AAAA,KACF;AACA,IAAS,MAAA,GAAA,IAAA,CAAA;AAAA,GACX;AACA,EAAO,OAAA,MAAA,CAAA;AACT,CAAA;AAGO,SAAS,WAAW,IAA2C,EAAA;AACpE,EAAI,IAAA,KAAA,CAAM,OAAQ,CAAA,IAAI,CAAG,EAAA;AACvB,IAAA,MAAM,SAAiB,EAAC,CAAA;AACxB,IAAA,KAAA,MAAW,OAAO,IAAM,EAAA;AACtB,MAAA,MAAA,CAAO,GAAU,CAAI,GAAA,GAAA,CAAA;AAAA,KACvB;AACA,IAAO,OAAA,MAAA,CAAA;AAAA,GACT,MAAA,IAAW,OAAO,IAAA,KAAS,QAAU,EAAA;AACnC,IAAO,OAAA,IAAA,CAAA;AAAA,GACT;AAEA,EAAA,OAAO,EAAE,CAAC,IAAI,GAAG,IAAY,EAAA,CAAA;AAC/B;;;;"}
|
package/dist/es/fill.js
CHANGED
|
@@ -5,11 +5,18 @@ function fill(keys) {
|
|
|
5
5
|
const keysArray = singleOrArray(keys);
|
|
6
6
|
const replaceMap = {};
|
|
7
7
|
return items.map((d) => {
|
|
8
|
-
|
|
8
|
+
let needsCopy = false;
|
|
9
9
|
for (const key of keysArray) {
|
|
10
|
-
if (
|
|
11
|
-
replaceMap[key] =
|
|
10
|
+
if (d[key] != null) {
|
|
11
|
+
replaceMap[key] = d[key];
|
|
12
12
|
} else if (replaceMap[key] != null) {
|
|
13
|
+
needsCopy = true;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if (!needsCopy) return d;
|
|
17
|
+
const obj = { ...d };
|
|
18
|
+
for (const key of keysArray) {
|
|
19
|
+
if (obj[key] == null && replaceMap[key] != null) {
|
|
13
20
|
obj[key] = replaceMap[key];
|
|
14
21
|
}
|
|
15
22
|
}
|
package/dist/es/fill.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fill.js","sources":["../../src/fill.ts"],"sourcesContent":["import { SingleOrArray, singleOrArray } from './helpers/singleOrArray';\nimport { Key, TidyFn } from './types';\n\n/**\n * Fills values for the specified keys to match the last seen value in the collection.\n */\nexport function fill<T extends object>(keys: SingleOrArray<Key>): TidyFn<T> {\n const _fill: TidyFn<T> = (items: T[]): T[] => {\n const keysArray = singleOrArray(keys);\n\n const replaceMap: Partial<T> = {};\n\n return items.map((d) => {\n
|
|
1
|
+
{"version":3,"file":"fill.js","sources":["../../src/fill.ts"],"sourcesContent":["import { SingleOrArray, singleOrArray } from './helpers/singleOrArray';\nimport { Key, TidyFn } from './types';\n\n/**\n * Fills values for the specified keys to match the last seen value in the collection.\n */\nexport function fill<T extends object>(keys: SingleOrArray<Key>): TidyFn<T> {\n const _fill: TidyFn<T> = (items: T[]): T[] => {\n const keysArray = singleOrArray(keys);\n\n const replaceMap: Partial<T> = {};\n\n return items.map((d) => {\n let needsCopy = false;\n for (const key of keysArray) {\n if (d[key as keyof T] != null) {\n replaceMap[key as keyof T] = d[key as keyof T];\n } else if (replaceMap[key as keyof T] != null) {\n needsCopy = true;\n }\n }\n if (!needsCopy) return d;\n const obj = { ...d };\n for (const key of keysArray) {\n if (obj[key as keyof T] == null && replaceMap[key as keyof T] != null) {\n obj[key as keyof T] = replaceMap[key as keyof T] as any;\n }\n }\n return obj;\n });\n };\n\n return _fill;\n}\n"],"names":[],"mappings":";;AAMO,SAAS,KAAuB,IAAqC,EAAA;AAC1E,EAAM,MAAA,KAAA,GAAmB,CAAC,KAAoB,KAAA;AAC5C,IAAM,MAAA,SAAA,GAAY,cAAc,IAAI,CAAA,CAAA;AAEpC,IAAA,MAAM,aAAyB,EAAC,CAAA;AAEhC,IAAO,OAAA,KAAA,CAAM,GAAI,CAAA,CAAC,CAAM,KAAA;AACtB,MAAA,IAAI,SAAY,GAAA,KAAA,CAAA;AAChB,MAAA,KAAA,MAAW,OAAO,SAAW,EAAA;AAC3B,QAAI,IAAA,CAAA,CAAE,GAAc,CAAA,IAAK,IAAM,EAAA;AAC7B,UAAW,UAAA,CAAA,GAAc,CAAI,GAAA,CAAA,CAAE,GAAc,CAAA,CAAA;AAAA,SACpC,MAAA,IAAA,UAAA,CAAW,GAAc,CAAA,IAAK,IAAM,EAAA;AAC7C,UAAY,SAAA,GAAA,IAAA,CAAA;AAAA,SACd;AAAA,OACF;AACA,MAAI,IAAA,CAAC,WAAkB,OAAA,CAAA,CAAA;AACvB,MAAM,MAAA,GAAA,GAAM,EAAE,GAAG,CAAE,EAAA,CAAA;AACnB,MAAA,KAAA,MAAW,OAAO,SAAW,EAAA;AAC3B,QAAA,IAAI,IAAI,GAAc,CAAA,IAAK,QAAQ,UAAW,CAAA,GAAc,KAAK,IAAM,EAAA;AACrE,UAAI,GAAA,CAAA,GAAc,CAAI,GAAA,UAAA,CAAW,GAAc,CAAA,CAAA;AAAA,SACjD;AAAA,OACF;AACA,MAAO,OAAA,GAAA,CAAA;AAAA,KACR,CAAA,CAAA;AAAA,GACH,CAAA;AAEA,EAAO,OAAA,KAAA,CAAA;AACT;;;;"}
|
package/dist/es/filter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter.js","sources":["../../src/filter.ts"],"sourcesContent":["import { TidyFn } from './types';\n\n/**\n * Filters items\n * @param filterFn Returns true to keep the item, false to filter out\n */\nexport function filter<T extends object, O extends T>(\n filterFn: (item: T, index: number, array: T[]) => item is O\n): TidyFn<T, O>;\nexport function filter<T extends object>(\n filterFn: (item: T, index: number, array: T[]) => boolean\n): TidyFn<T>;\nexport function filter<T extends object>(\n filterFn: (item: T, index: number, array: T[]) => boolean\n): TidyFn<T> {\n const _filter: TidyFn<T> = (items: T[]): T[] => items.filter(filterFn);\n return _filter;\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"filter.js","sources":["../../src/filter.ts"],"sourcesContent":["import { TidyFn } from './types';\n\n/**\n * Filters items\n * @param filterFn Returns true to keep the item, false to filter out\n */\nexport function filter<T extends object, O extends T>(\n filterFn: (item: T, index: number, array: T[]) => item is O\n): TidyFn<T, O>;\nexport function filter<T extends object>(\n filterFn: (item: T, index: number, array: T[]) => boolean\n): TidyFn<T>;\nexport function filter<T extends object>(\n filterFn: (item: T, index: number, array: T[]) => boolean\n): TidyFn<T> {\n const _filter: TidyFn<T> = (items: T[]): T[] => items.filter(filterFn);\n return _filter;\n}\n"],"names":[],"mappings":"AAYO,SAAS,OACd,QACW,EAAA;AACX,EAAA,MAAM,OAAqB,GAAA,CAAC,KAAoB,KAAA,KAAA,CAAM,OAAO,QAAQ,CAAA,CAAA;AACrE,EAAO,OAAA,OAAA,CAAA;AACT;;;;"}
|
package/dist/es/fullJoin.js
CHANGED
|
@@ -1,33 +1,36 @@
|
|
|
1
|
-
import { autodetectByMap, makeByMap,
|
|
1
|
+
import { autodetectByMap, makeByMap, buildJoinIndex, computeKey } from './innerJoin.js';
|
|
2
2
|
|
|
3
3
|
function fullJoin(itemsToJoin, options) {
|
|
4
4
|
const _fullJoin = (items) => {
|
|
5
|
-
if (!itemsToJoin.length)
|
|
6
|
-
|
|
7
|
-
if (!items.length)
|
|
8
|
-
return itemsToJoin;
|
|
5
|
+
if (!itemsToJoin.length) return items;
|
|
6
|
+
if (!items.length) return itemsToJoin;
|
|
9
7
|
const byMap = (options == null ? void 0 : options.by) == null ? autodetectByMap(items, itemsToJoin) : makeByMap(options.by);
|
|
10
|
-
const
|
|
8
|
+
const joinKeys = Object.keys(byMap);
|
|
9
|
+
const itemKeys = joinKeys.map((jKey) => byMap[jKey]);
|
|
10
|
+
const index = buildJoinIndex(itemsToJoin, joinKeys);
|
|
11
|
+
const matchedItems = /* @__PURE__ */ new Set();
|
|
11
12
|
const joinObjectKeys = Object.keys(itemsToJoin[0]);
|
|
12
13
|
const joined = items.flatMap((d) => {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
const key = computeKey(d, itemKeys);
|
|
15
|
+
const matches = index.get(key);
|
|
16
|
+
if (matches !== void 0) {
|
|
17
|
+
for (const j of matches) {
|
|
18
|
+
matchedItems.add(j);
|
|
17
19
|
}
|
|
18
|
-
return
|
|
19
|
-
});
|
|
20
|
-
if (matches.length) {
|
|
21
|
-
return matches.map((j) => ({...d, ...j}));
|
|
20
|
+
return matches.map((j) => ({ ...d, ...j }));
|
|
22
21
|
}
|
|
23
|
-
const undefinedFill = Object.fromEntries(
|
|
24
|
-
|
|
22
|
+
const undefinedFill = Object.fromEntries(
|
|
23
|
+
joinObjectKeys.filter((key2) => d[key2] == null).map((key2) => [key2, void 0])
|
|
24
|
+
);
|
|
25
|
+
return { ...d, ...undefinedFill };
|
|
25
26
|
});
|
|
26
|
-
if (
|
|
27
|
-
const leftEmptyObject = Object.fromEntries(
|
|
27
|
+
if (matchedItems.size < itemsToJoin.length) {
|
|
28
|
+
const leftEmptyObject = Object.fromEntries(
|
|
29
|
+
Object.keys(items[0]).map((key) => [key, void 0])
|
|
30
|
+
);
|
|
28
31
|
for (const item of itemsToJoin) {
|
|
29
|
-
if (!
|
|
30
|
-
joined.push({...leftEmptyObject, ...item});
|
|
32
|
+
if (!matchedItems.has(item)) {
|
|
33
|
+
joined.push({ ...leftEmptyObject, ...item });
|
|
31
34
|
}
|
|
32
35
|
}
|
|
33
36
|
}
|
package/dist/es/fullJoin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fullJoin.js","sources":["../../src/fullJoin.ts"],"sourcesContent":["import { Datum, TidyFn } from './types';\nimport {
|
|
1
|
+
{"version":3,"file":"fullJoin.js","sources":["../../src/fullJoin.ts"],"sourcesContent":["import { Datum, TidyFn } from './types';\nimport {\n makeByMap,\n autodetectByMap,\n JoinOptions,\n buildJoinIndex,\n computeKey,\n} from './innerJoin';\nimport { Merge } from './type-utils';\n\n/**\n * Performs a full join on two collections\n * @param itemsToJoin The rows/items to be appended to end of collection\n */\nexport function fullJoin<T extends Datum, JoinT extends Datum>(\n itemsToJoin: JoinT[],\n options?: JoinOptions<JoinT, T> | null | undefined\n): TidyFn<T, Merge<T, Partial<JoinT>>> {\n const _fullJoin: TidyFn<T, Merge<T, Partial<JoinT>>> = (\n items: T[]\n ): Merge<T, Partial<JoinT>>[] => {\n if (!itemsToJoin.length) return items as any;\n if (!items.length) return itemsToJoin as any;\n\n // convert by option in to a map from T key to JoinT key\n const byMap =\n options?.by == null\n ? autodetectByMap(items, itemsToJoin)\n : makeByMap(options.by);\n\n const joinKeys = Object.keys(byMap);\n const itemKeys = joinKeys.map((jKey) => byMap[jKey] as string);\n const index = buildJoinIndex(itemsToJoin, joinKeys);\n\n // keep track of matched join items by reference\n const matchedItems = new Set<JoinT>();\n\n // when we miss a join, we want to explicitly add in undefined\n // so our rows all have the same keys. get those keys here.\n const joinObjectKeys = Object.keys(itemsToJoin[0]);\n\n const joined = items.flatMap((d: T) => {\n const key = computeKey(d, itemKeys);\n const matches = index.get(key);\n\n if (matches !== undefined) {\n for (const j of matches) {\n matchedItems.add(j);\n }\n return matches.map((j: JoinT) => ({ ...d, ...j }));\n }\n\n // add in missing keys explicitly as undefined without\n // overriding existing values and while maintaining order\n // of keys\n const undefinedFill = Object.fromEntries(\n joinObjectKeys\n .filter((key) => d[key] == null)\n .map((key) => [key, undefined])\n );\n\n return { ...d, ...undefinedFill };\n });\n\n // add in the ones we missed\n if (matchedItems.size < itemsToJoin.length) {\n const leftEmptyObject = Object.fromEntries(\n Object.keys(items[0]).map((key) => [key, undefined])\n );\n for (const item of itemsToJoin) {\n if (!matchedItems.has(item)) {\n joined.push({ ...leftEmptyObject, ...item });\n }\n }\n }\n\n return joined;\n };\n return _fullJoin;\n}\n"],"names":["key"],"mappings":";;AAcgB,SAAA,QAAA,CACd,aACA,OACqC,EAAA;AACrC,EAAM,MAAA,SAAA,GAAiD,CACrD,KAC+B,KAAA;AAC/B,IAAI,IAAA,CAAC,WAAY,CAAA,MAAA,EAAe,OAAA,KAAA,CAAA;AAChC,IAAI,IAAA,CAAC,KAAM,CAAA,MAAA,EAAe,OAAA,WAAA,CAAA;AAG1B,IAAM,MAAA,KAAA,GAAA,CACJ,OAAS,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,OAAA,CAAA,EAAA,KAAM,IACX,GAAA,eAAA,CAAgB,OAAO,WAAW,CAAA,GAClC,SAAU,CAAA,OAAA,CAAQ,EAAE,CAAA,CAAA;AAE1B,IAAM,MAAA,QAAA,GAAW,MAAO,CAAA,IAAA,CAAK,KAAK,CAAA,CAAA;AAClC,IAAA,MAAM,WAAW,QAAS,CAAA,GAAA,CAAI,CAAC,IAAS,KAAA,KAAA,CAAM,IAAI,CAAW,CAAA,CAAA;AAC7D,IAAM,MAAA,KAAA,GAAQ,cAAe,CAAA,WAAA,EAAa,QAAQ,CAAA,CAAA;AAGlD,IAAM,MAAA,YAAA,uBAAmB,GAAW,EAAA,CAAA;AAIpC,IAAA,MAAM,cAAiB,GAAA,MAAA,CAAO,IAAK,CAAA,WAAA,CAAY,CAAC,CAAC,CAAA,CAAA;AAEjD,IAAA,MAAM,MAAS,GAAA,KAAA,CAAM,OAAQ,CAAA,CAAC,CAAS,KAAA;AACrC,MAAM,MAAA,GAAA,GAAM,UAAW,CAAA,CAAA,EAAG,QAAQ,CAAA,CAAA;AAClC,MAAM,MAAA,OAAA,GAAU,KAAM,CAAA,GAAA,CAAI,GAAG,CAAA,CAAA;AAE7B,MAAA,IAAI,YAAY,KAAW,CAAA,EAAA;AACzB,QAAA,KAAA,MAAW,KAAK,OAAS,EAAA;AACvB,UAAA,YAAA,CAAa,IAAI,CAAC,CAAA,CAAA;AAAA,SACpB;AACA,QAAO,OAAA,OAAA,CAAQ,IAAI,CAAC,CAAA,MAAc,EAAE,GAAG,CAAA,EAAG,GAAG,CAAA,EAAI,CAAA,CAAA,CAAA;AAAA,OACnD;AAKA,MAAA,MAAM,gBAAgB,MAAO,CAAA,WAAA;AAAA,QAC3B,cACG,CAAA,MAAA,CAAO,CAACA,IAAAA,KAAQ,EAAEA,IAAG,CAAA,IAAK,IAAI,CAAA,CAC9B,IAAI,CAACA,IAAAA,KAAQ,CAACA,IAAAA,EAAK,MAAS,CAAC,CAAA;AAAA,OAClC,CAAA;AAEA,MAAA,OAAO,EAAE,GAAG,CAAG,EAAA,GAAG,aAAc,EAAA,CAAA;AAAA,KACjC,CAAA,CAAA;AAGD,IAAI,IAAA,YAAA,CAAa,IAAO,GAAA,WAAA,CAAY,MAAQ,EAAA;AAC1C,MAAA,MAAM,kBAAkB,MAAO,CAAA,WAAA;AAAA,QAC7B,MAAO,CAAA,IAAA,CAAK,KAAM,CAAA,CAAC,CAAC,CAAA,CAAE,GAAI,CAAA,CAAC,GAAQ,KAAA,CAAC,GAAK,EAAA,KAAA,CAAS,CAAC,CAAA;AAAA,OACrD,CAAA;AACA,MAAA,KAAA,MAAW,QAAQ,WAAa,EAAA;AAC9B,QAAA,IAAI,CAAC,YAAA,CAAa,GAAI,CAAA,IAAI,CAAG,EAAA;AAC3B,UAAA,MAAA,CAAO,KAAK,EAAE,GAAG,eAAiB,EAAA,GAAG,MAAM,CAAA,CAAA;AAAA,SAC7C;AAAA,OACF;AAAA,KACF;AAEA,IAAO,OAAA,MAAA,CAAA;AAAA,GACT,CAAA;AACA,EAAO,OAAA,SAAA,CAAA;AACT;;;;"}
|
package/dist/es/groupBy.js
CHANGED
|
@@ -12,9 +12,13 @@ function groupBy(groupKeys, fns, options) {
|
|
|
12
12
|
} else if (arguments.length === 2 && fns != null && !Array.isArray(fns)) {
|
|
13
13
|
options = fns;
|
|
14
14
|
}
|
|
15
|
-
const _groupBy = (items) => {
|
|
15
|
+
const _groupBy = ((items) => {
|
|
16
16
|
const grouped = makeGrouped(items, groupKeys);
|
|
17
|
-
const results = runFlow(
|
|
17
|
+
const results = runFlow(
|
|
18
|
+
grouped,
|
|
19
|
+
fns,
|
|
20
|
+
options == null ? void 0 : options.addGroupKeys
|
|
21
|
+
);
|
|
18
22
|
if (options == null ? void 0 : options.export) {
|
|
19
23
|
switch (options.export) {
|
|
20
24
|
case "grouped":
|
|
@@ -38,29 +42,33 @@ function groupBy(groupKeys, fns, options) {
|
|
|
38
42
|
}
|
|
39
43
|
const ungrouped = ungroup(results, options == null ? void 0 : options.addGroupKeys);
|
|
40
44
|
return ungrouped;
|
|
41
|
-
};
|
|
45
|
+
});
|
|
42
46
|
return _groupBy;
|
|
43
47
|
}
|
|
44
|
-
groupBy.grouped = (options) => ({...options, export: "grouped"});
|
|
45
|
-
groupBy.entries = (options) => ({...options, export: "entries"});
|
|
46
|
-
groupBy.entriesObject = (options) => ({...options, export: "entries-object"});
|
|
47
|
-
groupBy.object = (options) => ({...options, export: "object"});
|
|
48
|
-
groupBy.map = (options) => ({...options, export: "map"});
|
|
49
|
-
groupBy.keys = (options) => ({...options, export: "keys"});
|
|
50
|
-
groupBy.values = (options) => ({...options, export: "values"});
|
|
51
|
-
groupBy.levels = (options) => ({...options, export: "levels"});
|
|
48
|
+
groupBy.grouped = (options) => ({ ...options, export: "grouped" });
|
|
49
|
+
groupBy.entries = (options) => ({ ...options, export: "entries" });
|
|
50
|
+
groupBy.entriesObject = (options) => ({ ...options, export: "entries-object" });
|
|
51
|
+
groupBy.object = (options) => ({ ...options, export: "object" });
|
|
52
|
+
groupBy.map = (options) => ({ ...options, export: "map" });
|
|
53
|
+
groupBy.keys = (options) => ({ ...options, export: "keys" });
|
|
54
|
+
groupBy.values = (options) => ({ ...options, export: "values" });
|
|
55
|
+
groupBy.levels = (options) => ({ ...options, export: "levels" });
|
|
52
56
|
function runFlow(items, fns, addGroupKeys) {
|
|
53
57
|
let result = items;
|
|
54
|
-
if (!(fns == null ? void 0 : fns.length))
|
|
55
|
-
return result;
|
|
58
|
+
if (!(fns == null ? void 0 : fns.length)) return result;
|
|
56
59
|
for (const fn of fns) {
|
|
57
|
-
if (!fn)
|
|
58
|
-
continue;
|
|
60
|
+
if (!fn) continue;
|
|
59
61
|
result = groupMap(result, (items2, keys) => {
|
|
60
|
-
const
|
|
62
|
+
const keysSnapshot = keys.slice();
|
|
63
|
+
const context = { groupKeys: keysSnapshot };
|
|
61
64
|
let leafItemsMapped = fn(items2, context);
|
|
62
65
|
if (addGroupKeys !== false) {
|
|
63
|
-
|
|
66
|
+
const filteredKeys = keysSnapshot.filter(
|
|
67
|
+
(key) => typeof key[0] !== "function" && key[0] != null
|
|
68
|
+
);
|
|
69
|
+
leafItemsMapped = leafItemsMapped.map(
|
|
70
|
+
(item) => assignGroupKeys(item, keysSnapshot, filteredKeys)
|
|
71
|
+
);
|
|
64
72
|
}
|
|
65
73
|
return leafItemsMapped;
|
|
66
74
|
});
|
|
@@ -68,9 +76,9 @@ function runFlow(items, fns, addGroupKeys) {
|
|
|
68
76
|
return result;
|
|
69
77
|
}
|
|
70
78
|
function makeGrouped(items, groupKeys) {
|
|
71
|
-
const groupKeyFns = singleOrArray(groupKeys).map((key
|
|
79
|
+
const groupKeyFns = singleOrArray(groupKeys).map((key) => {
|
|
72
80
|
const keyFn = typeof key === "function" ? key : (d) => d[key];
|
|
73
|
-
const keyCache = new Map();
|
|
81
|
+
const keyCache = /* @__PURE__ */ new Map();
|
|
74
82
|
return (d) => {
|
|
75
83
|
const keyValue = keyFn(d);
|
|
76
84
|
const keyValueOf = isObject(keyValue) ? keyValue.valueOf() : keyValue;
|
|
@@ -90,7 +98,10 @@ function ungroup(grouped, addGroupKeys) {
|
|
|
90
98
|
groupTraversal(grouped, items, [], identity, (root, keys, values) => {
|
|
91
99
|
let valuesToAdd = values;
|
|
92
100
|
if (addGroupKeys !== false) {
|
|
93
|
-
|
|
101
|
+
const filteredKeys = keys.filter(
|
|
102
|
+
(key) => typeof key[0] !== "function" && key[0] != null
|
|
103
|
+
);
|
|
104
|
+
valuesToAdd = values.map((d) => assignGroupKeys(d, keys, filteredKeys));
|
|
94
105
|
}
|
|
95
106
|
root.push(...valuesToAdd);
|
|
96
107
|
});
|
|
@@ -111,23 +122,30 @@ function processFromGroupsOptions(options) {
|
|
|
111
122
|
compositeKey = (_a = options.compositeKey) != null ? _a : defaultCompositeKey;
|
|
112
123
|
}
|
|
113
124
|
const groupFn = (values, keys) => {
|
|
114
|
-
return single ? mapLeaf(
|
|
125
|
+
return single ? mapLeaf(
|
|
126
|
+
addGroupKeys === false ? values[0] : assignGroupKeys(values[0], keys)
|
|
127
|
+
) : mapLeaves(
|
|
128
|
+
values.map(
|
|
129
|
+
(d) => mapLeaf(addGroupKeys === false ? d : assignGroupKeys(d, keys))
|
|
130
|
+
)
|
|
131
|
+
);
|
|
115
132
|
};
|
|
116
133
|
const keyFn = flat ? (keys) => compositeKey(keys.map((d) => d[1])) : (keys) => keys[keys.length - 1][1];
|
|
117
|
-
return {groupFn, keyFn};
|
|
134
|
+
return { groupFn, keyFn };
|
|
118
135
|
}
|
|
119
136
|
function exportLevels(grouped, options) {
|
|
120
|
-
const {groupFn, keyFn} = processFromGroupsOptions(options);
|
|
121
|
-
let {mapEntry = identity} = options;
|
|
122
|
-
const {levels = ["entries"]} = options;
|
|
137
|
+
const { groupFn, keyFn } = processFromGroupsOptions(options);
|
|
138
|
+
let { mapEntry = identity } = options;
|
|
139
|
+
const { levels = ["entries"] } = options;
|
|
123
140
|
const levelSpecs = [];
|
|
124
141
|
for (const levelOption of levels) {
|
|
125
142
|
switch (levelOption) {
|
|
143
|
+
// entries / entries-object -----------------------------------------
|
|
126
144
|
case "entries":
|
|
127
145
|
case "entries-object":
|
|
128
146
|
case "entries-obj":
|
|
129
147
|
case "entriesObject": {
|
|
130
|
-
const levelMapEntry = (levelOption === "entries-object" || levelOption === "entries-obj" || levelOption === "entriesObject") && options.mapEntry == null ? ([key, values]) => ({key, values}) : mapEntry;
|
|
148
|
+
const levelMapEntry = (levelOption === "entries-object" || levelOption === "entries-obj" || levelOption === "entriesObject") && options.mapEntry == null ? ([key, values]) => ({ key, values }) : mapEntry;
|
|
131
149
|
levelSpecs.push({
|
|
132
150
|
id: "entries",
|
|
133
151
|
createEmptySubgroup: () => [],
|
|
@@ -140,10 +158,11 @@ function exportLevels(grouped, options) {
|
|
|
140
158
|
});
|
|
141
159
|
break;
|
|
142
160
|
}
|
|
161
|
+
// map -------------------------------------------------------------
|
|
143
162
|
case "map":
|
|
144
163
|
levelSpecs.push({
|
|
145
164
|
id: "map",
|
|
146
|
-
createEmptySubgroup: () => new Map(),
|
|
165
|
+
createEmptySubgroup: () => /* @__PURE__ */ new Map(),
|
|
147
166
|
addSubgroup: (parentGrouped, newSubgroup, key) => {
|
|
148
167
|
parentGrouped.set(key, newSubgroup);
|
|
149
168
|
},
|
|
@@ -152,6 +171,7 @@ function exportLevels(grouped, options) {
|
|
|
152
171
|
}
|
|
153
172
|
});
|
|
154
173
|
break;
|
|
174
|
+
// object ----------------------------------------------------------
|
|
155
175
|
case "object":
|
|
156
176
|
levelSpecs.push({
|
|
157
177
|
id: "object",
|
|
@@ -164,6 +184,7 @@ function exportLevels(grouped, options) {
|
|
|
164
184
|
}
|
|
165
185
|
});
|
|
166
186
|
break;
|
|
187
|
+
// keys ------------------------------------------------------------
|
|
167
188
|
case "keys":
|
|
168
189
|
levelSpecs.push({
|
|
169
190
|
id: "keys",
|
|
@@ -176,6 +197,7 @@ function exportLevels(grouped, options) {
|
|
|
176
197
|
}
|
|
177
198
|
});
|
|
178
199
|
break;
|
|
200
|
+
// values ----------------------------------------------------------
|
|
179
201
|
case "values":
|
|
180
202
|
levelSpecs.push({
|
|
181
203
|
id: "values",
|
|
@@ -188,6 +210,7 @@ function exportLevels(grouped, options) {
|
|
|
188
210
|
}
|
|
189
211
|
});
|
|
190
212
|
break;
|
|
213
|
+
// custom ----------------------------------------------------------
|
|
191
214
|
default: {
|
|
192
215
|
if (typeof levelOption === "object") {
|
|
193
216
|
levelSpecs.push(levelOption);
|
|
@@ -209,7 +232,12 @@ function exportLevels(grouped, options) {
|
|
|
209
232
|
const addLeaf = (parentGrouped, keys, values, level) => {
|
|
210
233
|
var _a;
|
|
211
234
|
const levelSpec = (_a = levelSpecs[level]) != null ? _a : levelSpecs[levelSpecs.length - 1];
|
|
212
|
-
levelSpec.addLeaf(
|
|
235
|
+
levelSpec.addLeaf(
|
|
236
|
+
parentGrouped,
|
|
237
|
+
keyFn(keys),
|
|
238
|
+
groupFn(values, keys),
|
|
239
|
+
level
|
|
240
|
+
);
|
|
213
241
|
};
|
|
214
242
|
const initialOutputObject = levelSpecs[0].createEmptySubgroup();
|
|
215
243
|
return groupTraversal(grouped, initialOutputObject, [], addSubgroup, addLeaf);
|