Avoid the performance/memory overheads of "clone on modify" of $args (#1884)

* Avoid the performance/memory overheads of "clone on modify" of $args when building the condition set/database for AVERAGEIFS(), MAXIFS() and MINIFS()
* Avoid the performance/memory overheads of "clone on modify" of $args when building the condition set/database for COUNTIFS()
This commit is contained in:
Mark Baker 2021-02-27 23:10:33 +01:00 committed by GitHub
parent 80a20fc991
commit 761c84a946
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 45 additions and 31 deletions

View File

@ -67,8 +67,8 @@ class Conditional
return self::AVERAGEIF($args[2], $args[1], $args[0]); return self::AVERAGEIF($args[2], $args[1], $args[0]);
} }
$conditions = self::buildConditionSet(...$args); $conditions = self::buildConditionSetForRange(...$args);
$database = self::buildDatabase(...$args); $database = self::buildDatabaseWithRange(...$args);
return DAverage::evaluate($database, self::VALUE_COLUMN_NAME, $conditions); return DAverage::evaluate($database, self::VALUE_COLUMN_NAME, $conditions);
} }
@ -122,19 +122,8 @@ class Conditional
return self::COUNTIF(...$args); return self::COUNTIF(...$args);
} }
$conditions = $database = []; $database = self::buildDatabase(...$args);
$pairCount = 1; $conditions = self::buildConditionSet(...$args);
while (count($args) > 0) {
$conditions[] = array_merge([sprintf(self::CONDITIONAL_COLUMN_NAME, $pairCount)], [array_pop($args)]);
$database[] = array_merge(
[sprintf(self::CONDITIONAL_COLUMN_NAME, $pairCount)],
Functions::flattenArray(array_pop($args))
);
++$pairCount;
}
$conditions = array_map(null, ...$conditions);
$database = array_map(null, ...$database);
return DCount::evaluate($database, null, $conditions); return DCount::evaluate($database, null, $conditions);
} }
@ -157,8 +146,8 @@ class Conditional
return 0.0; return 0.0;
} }
$conditions = self::buildConditionSet(...$args); $conditions = self::buildConditionSetForRange(...$args);
$database = self::buildDatabase(...$args); $database = self::buildDatabaseWithRange(...$args);
return DMax::evaluate($database, self::VALUE_COLUMN_NAME, $conditions); return DMax::evaluate($database, self::VALUE_COLUMN_NAME, $conditions);
} }
@ -181,23 +170,22 @@ class Conditional
return 0.0; return 0.0;
} }
$conditions = self::buildConditionSet(...$args); $conditions = self::buildConditionSetForRange(...$args);
$database = self::buildDatabase(...$args); $database = self::buildDatabaseWithRange(...$args);
return DMin::evaluate($database, self::VALUE_COLUMN_NAME, $conditions); return DMin::evaluate($database, self::VALUE_COLUMN_NAME, $conditions);
} }
private static function buildConditionSet(...$args): array private static function buildConditionSet(...$args): array
{ {
array_shift($args); $conditions = self::buildConditions(1, ...$args);
$conditions = []; return array_map(null, ...$conditions);
$pairCount = 1; }
while (count($args) > 0) {
$conditions[] = array_merge([sprintf(self::CONDITIONAL_COLUMN_NAME, $pairCount)], [array_pop($args)]); private static function buildConditionSetForRange(...$args): array
array_pop($args); {
++$pairCount; $conditions = self::buildConditions(2, ...$args);
}
if (count($conditions) === 1) { if (count($conditions) === 1) {
return array_map( return array_map(
@ -211,20 +199,46 @@ class Conditional
return array_map(null, ...$conditions); return array_map(null, ...$conditions);
} }
private static function buildConditions(int $startOffset, ...$args): array
{
$conditions = [];
$pairCount = 1;
$argumentCount = count($args);
for ($argument = $startOffset; $argument < $argumentCount; $argument += 2) {
$conditions[] = array_merge([sprintf(self::CONDITIONAL_COLUMN_NAME, $pairCount)], [$args[$argument]]);
++$pairCount;
}
return $conditions;
}
private static function buildDatabase(...$args): array private static function buildDatabase(...$args): array
{
$database = [];
return self::buildDataSet(0, $database, ...$args);
}
private static function buildDatabaseWithRange(...$args): array
{ {
$database = []; $database = [];
$database[] = array_merge( $database[] = array_merge(
[self::VALUE_COLUMN_NAME], [self::VALUE_COLUMN_NAME],
Functions::flattenArray(array_shift($args)) Functions::flattenArray($args[0])
); );
return self::buildDataSet(1, $database, ...$args);
}
private static function buildDataSet(int $startOffset, array $database, ...$args): array
{
$pairCount = 1; $pairCount = 1;
while (count($args) > 0) { $argumentCount = count($args);
array_pop($args); for ($argument = $startOffset; $argument < $argumentCount; $argument += 2) {
$database[] = array_merge( $database[] = array_merge(
[sprintf(self::CONDITIONAL_COLUMN_NAME, $pairCount)], [sprintf(self::CONDITIONAL_COLUMN_NAME, $pairCount)],
Functions::flattenArray(array_pop($args)) Functions::flattenArray($args[$argument])
); );
++$pairCount; ++$pairCount;
} }