Skip to content

Commit c118234

Browse files
author
Rene Kretzschmar
committed
feat(function): add MINIFS and MAXIFS
1 parent 52b284f commit c118234

21 files changed

+451
-0
lines changed

docs/guide/built-in-functions.md

+2
Original file line numberDiff line numberDiff line change
@@ -426,9 +426,11 @@ Total number of functions: **{{ $page.functionsCount }}**
426426
| LOGINV | Returns value of inverse lognormal distribution. | LOGINV(P; Mean; Stddev) |
427427
| MAX | Returns the maximum value in a list of arguments. | MAX(Number1; Number2; ...Number30) |
428428
| MAXA | Returns the maximum value in a list of arguments. | MAXA(Value1; Value2; ... Value30) |
429+
| MAXIFS | Returns the max of the values of cells in a range that meets multiple criteria in multiple ranges. | MAXIFS(Max_Range ; Criterion_range1 ; Criterion1 [ ; Criterion_range2 ; Criterion2 [;...]]) |
429430
| MEDIAN | Returns the median of a set of numbers. | MEDIAN(Number1; Number2; ...Number30) |
430431
| MIN | Returns the minimum value in a list of arguments. | MIN(Number1; Number2; ...Number30) |
431432
| MINA | Returns the minimum value in a list of arguments. | MINA(Value1; Value2; ... Value30) |
433+
| MINIFS | Returns the min of the values of cells in a range that meets multiple criteria in multiple ranges. | MINIFS(Min_Range ; Criterion_range1 ; Criterion1 [ ; Criterion_range2 ; Criterion2 [;...]]) |
432434
| NEGBINOM.DIST | Returns density of negative binomial distribution. | NEGBINOM.DIST(Number1; Number2; Number3; Mode) |
433435
| NEGBINOMDIST | Returns density of negative binomial distribution. | NEGBINOMDIST(Number1; Number2; Number3; Mode) |
434436
| NORM.DIST | Returns density of normal distribution. | NORM.DIST(X; Mean; Stddev; Mode) |

src/i18n/languages/csCZ.ts

+2
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,14 @@ const dictionary: RawTranslationPackage = {
133133
MATCH: 'POZVYHLEDAT',
134134
MAX: 'MAX',
135135
MAXA: 'MAXA',
136+
MAXIFS: 'MAXIFS',
136137
MAXPOOL: 'MAXPOOL',
137138
MEDIAN: 'MEDIAN',
138139
MEDIANPOOL: 'MEDIANPOOL',
139140
MID: 'ČÁST',
140141
MIN: 'MIN',
141142
MINA: 'MINA',
143+
MINIFS: 'MINIFS',
142144
MINUTE: 'MINUTA',
143145
MIRR: 'MOD.MÍRA.VÝNOSNOSTI',
144146
MMULT: 'SOUČIN.MATIC',

src/i18n/languages/daDK.ts

+2
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,14 @@ const dictionary: RawTranslationPackage = {
133133
MATCH: 'SAMMENLIGN',
134134
MAX: 'MAKS',
135135
MAXA: 'MAKSV',
136+
MAXIFS: 'MAXIFS',
136137
MAXPOOL: 'MAXPOOL',
137138
MEDIAN: 'MEDIAN',
138139
MEDIANPOOL: 'MEDIANPOOL',
139140
MID: 'MIDT',
140141
MIN: 'MIN',
141142
MINA: 'MINV',
143+
MINIFS: 'MINIFS',
142144
MINUTE: 'MINUT',
143145
MIRR: 'MIA',
144146
MMULT: 'MPRODUKT',

src/i18n/languages/deDE.ts

+2
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,14 @@ const dictionary: RawTranslationPackage = {
133133
MATCH: 'VERGLEICH',
134134
MAX: 'MAX',
135135
MAXA: 'MAXA',
136+
MAXIFS: 'MAXWENNS',
136137
MAXPOOL: 'MAXPOOL',
137138
MEDIAN: 'MEDIAN',
138139
MEDIANPOOL: 'MEDIANPOOL',
139140
MID: 'TEIL',
140141
MIN: 'MIN',
141142
MINA: 'MINA',
143+
MINIFS: 'MINWENNS',
142144
MINUTE: 'MINUTE',
143145
MIRR: 'QIKV',
144146
MMULT: 'MMULT',

src/i18n/languages/enGB.ts

+2
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,14 @@ const dictionary: RawTranslationPackage = {
134134
MATCH: 'MATCH',
135135
MAX: 'MAX',
136136
MAXA: 'MAXA',
137+
MAXIFS: 'MAXIFS',
137138
MAXPOOL: 'MAXPOOL',
138139
MEDIAN: 'MEDIAN',
139140
MEDIANPOOL: 'MEDIANPOOL',
140141
MID: 'MID',
141142
MIN: 'MIN',
142143
MINA: 'MINA',
144+
MINIFS: 'MINIFS',
143145
MINUTE: 'MINUTE',
144146
MIRR: 'MIRR',
145147
MMULT: 'MMULT',

src/i18n/languages/esES.ts

+2
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,14 @@ export const dictionary: RawTranslationPackage = {
133133
MATCH: 'COINCIDIR',
134134
MAX: 'MAX',
135135
MAXA: 'MAXA',
136+
MAXIFS: 'MAXIFS',
136137
MAXPOOL: 'MAXPOOL',
137138
MEDIAN: 'MEDIANA',
138139
MEDIANPOOL: 'MEDIANPOOL',
139140
MID: 'EXTRAE',
140141
MIN: 'MIN',
141142
MINA: 'MINA',
143+
MINIFS: 'MINIFS',
142144
MINUTE: 'MINUTO',
143145
MIRR: 'TIRM',
144146
MMULT: 'MMULT',

src/i18n/languages/fiFI.ts

+2
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,14 @@ const dictionary: RawTranslationPackage = {
133133
MATCH: 'VASTINE',
134134
MAX: 'MAKS',
135135
MAXA: 'MAKSA',
136+
MAXIFS: 'MAXIFS',
136137
MAXPOOL: 'MAXPOOL',
137138
MEDIAN: 'MEDIAANI',
138139
MEDIANPOOL: 'MEDIANPOOL',
139140
MID: 'POIMI.TEKSTI',
140141
MIN: 'MIN',
141142
MINA: 'MINA',
143+
MINIFS: 'MINIFS',
142144
MINUTE: 'MINUUTIT',
143145
MIRR: 'MSISÄINEN',
144146
MMULT: 'MKERRO',

src/i18n/languages/frFR.ts

+2
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,14 @@ const dictionary: RawTranslationPackage = {
133133
MATCH: 'EQUIV',
134134
MAX: 'MAX',
135135
MAXA: 'MAXA',
136+
MAXIFS: 'MAXIFS',
136137
MAXPOOL: 'MAXPOOL',
137138
MEDIAN: 'MEDIANE',
138139
MEDIANPOOL: 'MEDIANPOOL',
139140
MID: 'STXT',
140141
MIN: 'MIN',
141142
MINA: 'MINA',
143+
MINIFS: 'MINIFS',
142144
MINUTE: 'MINUTE',
143145
MIRR: 'TRIM',
144146
MMULT: 'PRODUITMAT',

src/i18n/languages/huHU.ts

+2
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,14 @@ const dictionary: RawTranslationPackage = {
133133
MATCH: 'HOL.VAN',
134134
MAX: 'MAX',
135135
MAXA: 'MAXA',
136+
MAXIFS: 'MAXIFS',
136137
MAXPOOL: 'MAXPOOL',
137138
MEDIAN: 'MEDIÁN',
138139
MEDIANPOOL: 'MEDIANPOOL',
139140
MID: 'KÖZÉP',
140141
MIN: 'MIN',
141142
MINA: 'MINA',
143+
MINIFS: 'MINIFS',
142144
MINUTE: 'PERCEK',
143145
MIRR: 'MEGTÉRÜLÉS',
144146
MMULT: 'MSZORZAT',

src/i18n/languages/itIT.ts

+2
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,14 @@ const dictionary: RawTranslationPackage = {
133133
MATCH: 'CONFRONTA',
134134
MAX: 'MAX',
135135
MAXA: 'MAX.VALORI',
136+
MAXIFS: 'MAXIFS',
136137
MAXPOOL: 'MAXPOOL',
137138
MEDIAN: 'MEDIANA',
138139
MEDIANPOOL: 'MEDIANPOOL',
139140
MID: 'STRINGA.ESTRAI',
140141
MIN: 'MIN',
141142
MINA: 'MIN.VALORI',
143+
MINIFS: 'MINIFS',
142144
MINUTE: 'MINUTO',
143145
MIRR: 'TIR.VAR',
144146
MMULT: 'MATR.PRODOTTO',

src/i18n/languages/nbNO.ts

+2
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,14 @@ const dictionary: RawTranslationPackage = {
133133
MATCH: 'SAMMENLIGNE',
134134
MAX: 'STØRST',
135135
MAXA: 'MAKSA',
136+
MAXIFS: 'MAXIFS',
136137
MAXPOOL: 'MAXPOOL',
137138
MEDIAN: 'MEDIAN',
138139
MEDIANPOOL: 'MEDIANPOOL',
139140
MID: 'DELTEKST',
140141
MIN: 'MIN',
141142
MINA: 'MINA',
143+
MINIFS: 'MINIFS',
142144
MINUTE: 'MINUTT',
143145
MIRR: 'MODIR',
144146
MMULT: 'MMULT',

src/i18n/languages/nlNL.ts

+2
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,14 @@ const dictionary: RawTranslationPackage = {
133133
MATCH: 'VERGELIJKEN',
134134
MAX: 'MAX',
135135
MAXA: 'MAXA',
136+
MAXIFS: 'MAXIFS',
136137
MAXPOOL: 'MAXPOOL',
137138
MEDIAN: 'MEDIAAN',
138139
MEDIANPOOL: 'MEDIANPOOL',
139140
MID: 'DEEL',
140141
MIN: 'MIN',
141142
MINA: 'MINA',
143+
MINIFS: 'MINIFS',
142144
MINUTE: 'MINUUT',
143145
MIRR: 'GIR',
144146
MMULT: 'PRODUCTMAT',

src/i18n/languages/plPL.ts

+2
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,14 @@ const dictionary: RawTranslationPackage = {
133133
MATCH: 'PODAJ.POZYCJĘ',
134134
MAX: 'MAKS',
135135
MAXA: 'MAX.A',
136+
MAXIFS: 'MAXIFS',
136137
MAXPOOL: 'MAKS.Z.PULI',
137138
MEDIAN: 'MEDIANA',
138139
MEDIANPOOL: 'MEDIANA.Z.PULI',
139140
MID: 'FRAGMENT.TEKSTU',
140141
MIN: 'MIN',
141142
MINA: 'MIN.A',
143+
MINIFS: 'MINIFS',
142144
MINUTE: 'MINUTA',
143145
MIRR: 'MIRR',
144146
MMULT: 'MACIERZ.ILOCZYN',

src/i18n/languages/ptPT.ts

+2
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,14 @@ const dictionary: RawTranslationPackage = {
133133
MATCH: 'CORRESP',
134134
MAX: 'MÁXIMO',
135135
MAXA: 'MÁXIMOA',
136+
MAXIFS: 'MAXIFS',
136137
MAXPOOL: 'MAXPOOL',
137138
MEDIAN: 'MED',
138139
MEDIANPOOL: 'MEDIANPOOL',
139140
MID: 'EXT.TEXTO',
140141
MIN: 'MÍNIMO',
141142
MINA: 'MÍNIMOA',
143+
MINIFS: 'MINIFS',
142144
MINUTE: 'MINUTO',
143145
MIRR: 'MTIR',
144146
MMULT: 'MATRIZ.MULT',

src/i18n/languages/ruRU.ts

+2
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,14 @@ const dictionary: RawTranslationPackage = {
133133
MATCH: 'ПОИСКПОЗ',
134134
MAX: 'МАКС',
135135
MAXA: 'МАКСА',
136+
MAXIFS: 'MAXIFS',
136137
MAXPOOL: 'MAXPOOL',
137138
MEDIAN: 'МЕДИАНА',
138139
MEDIANPOOL: 'MEDIANPOOL',
139140
MID: 'ПСТР',
140141
MIN: 'МИН',
141142
MINA: 'МИНА',
143+
MINIFS: 'MINIFS',
142144
MINUTE: 'МИНУТЫ',
143145
MIRR: 'МВСД',
144146
MMULT: 'МУМНОЖ',

src/i18n/languages/svSE.ts

+2
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,14 @@ const dictionary: RawTranslationPackage = {
133133
MATCH: 'PASSA',
134134
MAX: 'MAX',
135135
MAXA: 'MAXA',
136+
MAXIFS: 'MAXIFS',
136137
MAXPOOL: 'MAXPOOL',
137138
MEDIAN: 'MEDIAN',
138139
MEDIANPOOL: 'MEDIANPOOL',
139140
MID: 'EXTEXT',
140141
MIN: 'MIN',
141142
MINA: 'MINA',
143+
MINIFS: 'MINIFS',
142144
MINUTE: 'MINUT',
143145
MIRR: 'MODIR',
144146
MMULT: 'MMULT',

src/i18n/languages/trTR.ts

+2
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,14 @@ const dictionary: RawTranslationPackage = {
133133
MATCH: 'KAÇINCI',
134134
MAX: 'MAK',
135135
MAXA: 'MAKA',
136+
MAXIFS: 'MAXIFS',
136137
MAXPOOL: 'MAXPOOL',
137138
MEDIAN: 'ORTANCA',
138139
MEDIANPOOL: 'MEDIANPOOL',
139140
MID: 'PARÇAAL',
140141
MIN: 'MİN',
141142
MINA: 'MİNA',
143+
MINIFS: 'MINIFS',
142144
MINUTE: 'DAKİKA',
143145
MIRR: 'D_İÇ_VERİM_ORANI',
144146
MMULT: 'DÇARP',
+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/**
2+
* @license
3+
* Copyright (c) 2021 Handsoncode. All rights reserved.
4+
*/
5+
6+
import {CellError, ErrorType} from '../../Cell'
7+
import {ErrorMessage} from '../../error-message'
8+
import {ProcedureAst} from '../../parser'
9+
import {Condition, CriterionFunctionCompute} from '../CriterionFunctionCompute'
10+
import {InterpreterState} from '../InterpreterState'
11+
import {getRawValue, InterpreterValue, RawScalarValue} from '../InterpreterValue'
12+
import {SimpleRangeValue} from '../SimpleRangeValue'
13+
import {ArgumentTypes, FunctionPlugin, FunctionPluginTypecheck} from './FunctionPlugin'
14+
15+
/** Computes key for criterion function cache */
16+
function minifsCacheKey(conditions: Condition[]): string {
17+
const conditionsStrings = conditions.map(
18+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19+
(c) => `${c.conditionRange.range!.sheet},${c.conditionRange.range!.start.col},${c.conditionRange.range!.start.row}`
20+
)
21+
return ['MINIFS', ...conditionsStrings].join(',')
22+
}
23+
24+
/** Computes key for criterion function cache */
25+
function maxifsCacheKey(conditions: Condition[]): string {
26+
const conditionsStrings = conditions.map(
27+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
28+
(c) => `${c.conditionRange.range!.sheet},${c.conditionRange.range!.start.col},${c.conditionRange.range!.start.row}`
29+
)
30+
return ['MAXIFS', ...conditionsStrings].join(',')
31+
}
32+
33+
export class MinMaxIfsPlugin extends FunctionPlugin implements FunctionPluginTypecheck<MinMaxIfsPlugin> {
34+
public static implementedFunctions = {
35+
MINIFS: {
36+
method: 'minifs',
37+
parameters: [
38+
{argumentType: ArgumentTypes.RANGE},
39+
{argumentType: ArgumentTypes.RANGE},
40+
{argumentType: ArgumentTypes.NOERROR},
41+
],
42+
repeatLastArgs: 2,
43+
},
44+
MAXIFS: {
45+
method: 'maxifs',
46+
parameters: [
47+
{argumentType: ArgumentTypes.RANGE},
48+
{argumentType: ArgumentTypes.RANGE},
49+
{argumentType: ArgumentTypes.NOERROR},
50+
],
51+
repeatLastArgs: 2,
52+
},
53+
}
54+
55+
public minifs(ast: ProcedureAst, state: InterpreterState): InterpreterValue {
56+
return this.compute(ast, state, minifsCacheKey, Number.POSITIVE_INFINITY, (left, right) => Math.min(left, right))
57+
}
58+
59+
public maxifs(ast: ProcedureAst, state: InterpreterState): InterpreterValue {
60+
return this.compute(ast, state, maxifsCacheKey, Number.NEGATIVE_INFINITY, (left, right) => Math.max(left, right))
61+
}
62+
63+
private compute(
64+
ast: ProcedureAst,
65+
state: InterpreterState,
66+
cacheKey: (conditions: Condition[]) => string,
67+
initialValue: RawScalarValue,
68+
fn: (left: number, right: number) => number
69+
): InterpreterValue {
70+
return this.runFunction(ast.args, state, this.metadata('MINIFS'), (values: SimpleRangeValue, ...args) => {
71+
const conditions: Condition[] = []
72+
for (let i = 0; i < args.length; i += 2) {
73+
const conditionArg = args[i] as SimpleRangeValue
74+
const criterionPackage = this.interpreter.criterionBuilder.fromCellValue(args[i + 1], this.arithmeticHelper)
75+
if (criterionPackage === undefined) {
76+
return new CellError(ErrorType.VALUE, ErrorMessage.BadCriterion)
77+
}
78+
conditions.push(new Condition(conditionArg, criterionPackage))
79+
}
80+
81+
return new CriterionFunctionCompute<RawScalarValue>(
82+
this.interpreter,
83+
cacheKey,
84+
initialValue,
85+
(left, right) => {
86+
if (left instanceof CellError) {
87+
return left
88+
} else if (right instanceof CellError) {
89+
return right
90+
} else if (typeof left === 'number') {
91+
if (typeof right === 'number') {
92+
return fn(left, right)
93+
} else {
94+
return left
95+
}
96+
} else if (typeof right === 'number') {
97+
return right
98+
} else {
99+
return 0
100+
}
101+
},
102+
(arg) => getRawValue(arg)
103+
).compute(values, conditions)
104+
})
105+
}
106+
}

src/interpreter/plugin/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,4 @@ export {StatisticalPlugin} from './StatisticalPlugin'
4444
export {MathPlugin} from './MathPlugin'
4545
export {ComplexPlugin} from './ComplexPlugin'
4646
export {StatisticalAggregationPlugin} from './StatisticalAggregationPlugin'
47+
export {MinMaxIfsPlugin} from './MinMaxIfsPlugin'

0 commit comments

Comments
 (0)