210 lines
5.2 KiB
PHP
210 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Engine;
|
|
|
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
|
|
|
class ArrayArgumentHelper
|
|
{
|
|
/**
|
|
* @var int
|
|
*/
|
|
protected $indexStart = 0;
|
|
|
|
/**
|
|
* @var array
|
|
*/
|
|
protected $arguments;
|
|
|
|
/**
|
|
* @var int
|
|
*/
|
|
protected $argumentCount;
|
|
|
|
/**
|
|
* @var array
|
|
*/
|
|
protected $rows;
|
|
|
|
/**
|
|
* @var array
|
|
*/
|
|
protected $columns;
|
|
|
|
public function initialise(array $arguments): void
|
|
{
|
|
$keys = array_keys($arguments);
|
|
$this->indexStart = (int) array_shift($keys);
|
|
$this->rows = $this->rows($arguments);
|
|
$this->columns = $this->columns($arguments);
|
|
|
|
$this->argumentCount = count($arguments);
|
|
$this->arguments = $this->flattenSingleCellArrays($arguments, $this->rows, $this->columns);
|
|
|
|
$this->rows = $this->rows($arguments);
|
|
$this->columns = $this->columns($arguments);
|
|
|
|
if ($this->arrayArguments() > 2) {
|
|
throw new Exception('Formulae with more than two array arguments are not supported');
|
|
}
|
|
}
|
|
|
|
public function arguments(): array
|
|
{
|
|
return $this->arguments;
|
|
}
|
|
|
|
public function hasArrayArgument(): bool
|
|
{
|
|
return $this->arrayArguments() > 0;
|
|
}
|
|
|
|
public function getFirstArrayArgumentNumber(): int
|
|
{
|
|
$rowArrays = $this->filterArray($this->rows);
|
|
$columnArrays = $this->filterArray($this->columns);
|
|
|
|
for ($index = $this->indexStart; $index < $this->argumentCount; ++$index) {
|
|
if (isset($rowArrays[$index]) || isset($columnArrays[$index])) {
|
|
return ++$index;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public function getSingleRowVector(): ?int
|
|
{
|
|
$rowVectors = $this->getRowVectors();
|
|
|
|
return count($rowVectors) === 1 ? array_pop($rowVectors) : null;
|
|
}
|
|
|
|
private function getRowVectors(): array
|
|
{
|
|
$rowVectors = [];
|
|
for ($index = $this->indexStart; $index < ($this->indexStart + $this->argumentCount); ++$index) {
|
|
if ($this->rows[$index] === 1 && $this->columns[$index] > 1) {
|
|
$rowVectors[] = $index;
|
|
}
|
|
}
|
|
|
|
return $rowVectors;
|
|
}
|
|
|
|
public function getSingleColumnVector(): ?int
|
|
{
|
|
$columnVectors = $this->getColumnVectors();
|
|
|
|
return count($columnVectors) === 1 ? array_pop($columnVectors) : null;
|
|
}
|
|
|
|
private function getColumnVectors(): array
|
|
{
|
|
$columnVectors = [];
|
|
for ($index = $this->indexStart; $index < ($this->indexStart + $this->argumentCount); ++$index) {
|
|
if ($this->rows[$index] > 1 && $this->columns[$index] === 1) {
|
|
$columnVectors[] = $index;
|
|
}
|
|
}
|
|
|
|
return $columnVectors;
|
|
}
|
|
|
|
public function getMatrixPair(): array
|
|
{
|
|
for ($i = $this->indexStart; $i < ($this->indexStart + $this->argumentCount - 1); ++$i) {
|
|
for ($j = $i + 1; $j < $this->argumentCount; ++$j) {
|
|
if (isset($this->rows[$i], $this->rows[$j])) {
|
|
return [$i, $j];
|
|
}
|
|
}
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
public function isVector(int $argument): bool
|
|
{
|
|
return $this->rows[$argument] === 1 || $this->columns[$argument] === 1;
|
|
}
|
|
|
|
public function isRowVector(int $argument): bool
|
|
{
|
|
return $this->rows[$argument] === 1;
|
|
}
|
|
|
|
public function isColumnVector(int $argument): bool
|
|
{
|
|
return $this->columns[$argument] === 1;
|
|
}
|
|
|
|
public function rowCount(int $argument): int
|
|
{
|
|
return $this->rows[$argument];
|
|
}
|
|
|
|
public function columnCount(int $argument): int
|
|
{
|
|
return $this->columns[$argument];
|
|
}
|
|
|
|
private function rows(array $arguments): array
|
|
{
|
|
return array_map(
|
|
function ($argument) {
|
|
return is_countable($argument) ? count($argument) : 1;
|
|
},
|
|
$arguments
|
|
);
|
|
}
|
|
|
|
private function columns(array $arguments): array
|
|
{
|
|
return array_map(
|
|
function ($argument) {
|
|
return is_array($argument) && is_array($argument[array_keys($argument)[0]])
|
|
? count($argument[array_keys($argument)[0]])
|
|
: 1;
|
|
},
|
|
$arguments
|
|
);
|
|
}
|
|
|
|
public function arrayArguments(): int
|
|
{
|
|
$count = 0;
|
|
foreach (array_keys($this->arguments) as $argument) {
|
|
if ($this->rows[$argument] > 1 || $this->columns[$argument] > 1) {
|
|
++$count;
|
|
}
|
|
}
|
|
|
|
return $count;
|
|
}
|
|
|
|
private function flattenSingleCellArrays(array $arguments, array $rows, array $columns): array
|
|
{
|
|
foreach ($arguments as $index => $argument) {
|
|
if ($rows[$index] === 1 && $columns[$index] === 1) {
|
|
while (is_array($argument)) {
|
|
$argument = array_pop($argument);
|
|
}
|
|
$arguments[$index] = $argument;
|
|
}
|
|
}
|
|
|
|
return $arguments;
|
|
}
|
|
|
|
private function filterArray(array $array): array
|
|
{
|
|
return array_filter(
|
|
$array,
|
|
function ($value) {
|
|
return $value > 1;
|
|
}
|
|
);
|
|
}
|
|
}
|