Reducers: Update percentile logic - move percentiles to after standard reducers (#86004)

* baldm0mma/pth_fix2/ move percentiles to after standard reducers

* baldm0mma/pth_fix2/ update ordinal suffix

---------

Co-authored-by: nmarrs <nathanielmarrs@gmail.com>
This commit is contained in:
Jev Forsberg 2024-04-17 07:01:13 -06:00 committed by GitHub
parent 0a12ad0084
commit f9af4675ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 29 additions and 20 deletions

View File

@ -252,17 +252,19 @@ describe('Stats Calculators', () => {
expect(reduce(someNulls, ReducerID.count)).toEqual(4); expect(reduce(someNulls, ReducerID.count)).toEqual(4);
}); });
for (let i = 1; i < 100; i++) { it('can reduce to percentiles', () => {
it(`can reduce the ${i}th percentile`, () => { // This `Array.from` will build an array of elements from 1 to 99
const percentiles = [...Array.from({ length: 99 }, (_, i) => i + 1)];
percentiles.forEach((percentile) => {
const preciseStats = reduceField({ const preciseStats = reduceField({
field: createField( field: createField(
'x', 'x',
Array.from({ length: 101 }, (_, index) => index) Array.from({ length: 101 }, (_, index) => index)
), ),
reducers: [(ReducerID as Record<string, ReducerID>)[`p${i}`]], reducers: [(ReducerID as Record<string, ReducerID>)[`p${percentile}`]],
}); });
expect(preciseStats[`p${i}`]).toEqual(i); expect(preciseStats[`p${percentile}`]).toEqual(percentile);
}); });
} });
}); });

View File

@ -402,27 +402,34 @@ export const fieldReducers = new Registry<FieldReducerInfo>(() => [
}), }),
preservesUnits: false, preservesUnits: false,
}, },
...buildPercentileReducers(),
]); ]);
for (let i = 1; i < 100; i++) { // This `Array.from` will build an array of elements from 1 to 99
const percentile = i / 100; const buildPercentileReducers = (percentiles = [...Array.from({ length: 99 }, (_, i) => i + 1)]) => {
const id = `p${i}` as ReducerID; const percentileReducers: FieldReducerInfo[] = [];
const nth = (n: number) => const nth = (n: number) =>
n > 3 && n < 21 ? 'th' : n % 10 === 1 ? 'st' : n % 10 === 2 ? 'nd' : n % 10 === 3 ? 'rd' : 'th'; n > 3 && n < 21 ? 'th' : n % 10 === 1 ? 'st' : n % 10 === 2 ? 'nd' : n % 10 === 3 ? 'rd' : 'th';
const name = `${i}${nth(i)} percentile`;
const description = `${i}${nth(i)} percentile value`;
fieldReducers.register({ percentiles.forEach((p) => {
id: id, const percentile = p / 100;
name: name, const id = `p${p}` as ReducerID;
description: description, const name = `${p}${nth(p)} %`;
standard: false, const description = `${p}${nth(p)} percentile value`;
reduce: (field: Field, ignoreNulls: boolean, nullAsZero: boolean): FieldCalcs => {
return { [id]: calculatePercentile(field, percentile, ignoreNulls, nullAsZero) }; percentileReducers.push({
}, id: id,
preservesUnits: true, name: name,
description: description,
standard: false,
reduce: (field: Field, ignoreNulls: boolean, nullAsZero: boolean): FieldCalcs => {
return { [id]: calculatePercentile(field, percentile, ignoreNulls, nullAsZero) };
},
preservesUnits: true,
});
}); });
} return percentileReducers;
};
// Used for test cases // Used for test cases
export const defaultCalcs: FieldCalcs = { export const defaultCalcs: FieldCalcs = {