Skip to content

Commit

Permalink
Avoid the performance/memory overheads of "clone on modify" of $args (#…
Browse files Browse the repository at this point in the history
…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()
  • Loading branch information
Mark Baker committed Feb 27, 2021
1 parent 80a20fc commit 761c84a
Showing 1 changed file with 45 additions and 31 deletions.
76 changes: 45 additions & 31 deletions src/PhpSpreadsheet/Calculation/Statistical/Conditional.php
Expand Up @@ -67,8 +67,8 @@ public static function AVERAGEIFS(...$args)
return self::AVERAGEIF($args[2], $args[1], $args[0]);
}

$conditions = self::buildConditionSet(...$args);
$database = self::buildDatabase(...$args);
$conditions = self::buildConditionSetForRange(...$args);
$database = self::buildDatabaseWithRange(...$args);

return DAverage::evaluate($database, self::VALUE_COLUMN_NAME, $conditions);
}
Expand Down Expand Up @@ -122,19 +122,8 @@ public static function COUNTIFS(...$args)
return self::COUNTIF(...$args);
}

$conditions = $database = [];
$pairCount = 1;
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);
$database = self::buildDatabase(...$args);
$conditions = self::buildConditionSet(...$args);

return DCount::evaluate($database, null, $conditions);
}
Expand All @@ -157,8 +146,8 @@ public static function MAXIFS(...$args)
return 0.0;
}

$conditions = self::buildConditionSet(...$args);
$database = self::buildDatabase(...$args);
$conditions = self::buildConditionSetForRange(...$args);
$database = self::buildDatabaseWithRange(...$args);

return DMax::evaluate($database, self::VALUE_COLUMN_NAME, $conditions);
}
Expand All @@ -181,23 +170,22 @@ public static function MINIFS(...$args)
return 0.0;
}

$conditions = self::buildConditionSet(...$args);
$database = self::buildDatabase(...$args);
$conditions = self::buildConditionSetForRange(...$args);
$database = self::buildDatabaseWithRange(...$args);

return DMin::evaluate($database, self::VALUE_COLUMN_NAME, $conditions);
}

private static function buildConditionSet(...$args): array
{
array_shift($args);
$conditions = self::buildConditions(1, ...$args);

$conditions = [];
$pairCount = 1;
while (count($args) > 0) {
$conditions[] = array_merge([sprintf(self::CONDITIONAL_COLUMN_NAME, $pairCount)], [array_pop($args)]);
array_pop($args);
++$pairCount;
}
return array_map(null, ...$conditions);
}

private static function buildConditionSetForRange(...$args): array
{
$conditions = self::buildConditions(2, ...$args);

if (count($conditions) === 1) {
return array_map(
Expand All @@ -211,20 +199,46 @@ function ($value) {
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
{
$database = [];

return self::buildDataSet(0, $database, ...$args);
}

private static function buildDatabaseWithRange(...$args): array
{
$database = [];
$database[] = array_merge(
[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;
while (count($args) > 0) {
array_pop($args);
$argumentCount = count($args);
for ($argument = $startOffset; $argument < $argumentCount; $argument += 2) {
$database[] = array_merge(
[sprintf(self::CONDITIONAL_COLUMN_NAME, $pairCount)],
Functions::flattenArray(array_pop($args))
Functions::flattenArray($args[$argument])
);
++$pairCount;
}
Expand Down

0 comments on commit 761c84a

Please sign in to comment.