[$x]) : null, ...$array)); // @phpstan-ignore-line } /** @return mixed[] */ private static function arrayValues(mixed $array): array { return is_array($array) ? array_values($array) : [$array]; } /** * CHOOSECOLS. * * @param mixed $input expecting two-dimensional array * * @return mixed[]|string */ public static function chooseCols(mixed $input, mixed ...$args): array|string { if (!is_array($input)) { $input = [[$input]]; } $retval = self::chooseRows(self::transpose($input), ...$args); return is_array($retval) ? self::transpose($retval) : $retval; } /** * CHOOSEROWS. * * @param mixed $input expecting two-dimensional array * * @return mixed[]|string */ public static function chooseRows(mixed $input, mixed ...$args): array|string { if (!is_array($input)) { $input = [[$input]]; } $inputArray = [[]]; // no row 0 $numRows = 0; foreach ($input as $inputRow) { $inputArray[] = self::arrayValues($inputRow); ++$numRows; } $outputArray = []; foreach (Functions::flattenArray2(...$args) as $arg) { if (!is_numeric($arg)) { return ExcelError::VALUE(); } $index = (int) $arg; if ($index < 0) { $index += $numRows + 1; } if ($index <= 0 || $index > $numRows) { return ExcelError::VALUE(); } $outputArray[] = $inputArray[$index]; } return $outputArray; } private static function dropRows(array $array, mixed $offset): array|string { if ($offset === null) { return $array; } if (!is_numeric($offset)) { return ExcelError::VALUE(); } $offset = (int) $offset; $count = count($array); if (abs($offset) >= $count) { // In theory, this should be #CALC!, but Excel treats // #CALC! as corrupt, and it's not worth figuring out why return ExcelError::VALUE(); } if ($offset === 0) { return $array; } if ($offset > 0) { return array_slice($array, $offset); } return array_slice($array, 0, $count + $offset); } /** * DROP. * * @param mixed $input expect two-dimensional array * * @return mixed[]|string */ public static function drop(mixed $input, mixed $rows = null, mixed $columns = null): array|string { if (!is_array($input)) { $input = [[$input]]; } $inputArray = []; // no row 0 foreach ($input as $inputRow) { $inputArray[] = self::arrayValues($inputRow); } $outputArray1 = self::dropRows($inputArray, $rows); if (is_string($outputArray1)) { return $outputArray1; } $outputArray2 = self::transpose($outputArray1); $outputArray3 = self::dropRows($outputArray2, $columns); if (is_string($outputArray3)) { return $outputArray3; } return self::transpose($outputArray3); } private static function takeRows(array $array, mixed $offset): array|string { if ($offset === null) { return $array; } if (!is_numeric($offset)) { return ExcelError::VALUE(); } $offset = (int) $offset; if ($offset === 0) { // should be #CALC! - see above return ExcelError::VALUE(); } $count = count($array); if (abs($offset) >= $count) { return $array; } if ($offset > 0) { return array_slice($array, 0, $offset); } return array_slice($array, $count + $offset); } /** * TAKE. * * @param mixed $input expecting two-dimensional array * * @return mixed[]|string */ public static function take(mixed $input, mixed $rows, mixed $columns = null): array|string { if (!is_array($input)) { $input = [[$input]]; } if ($rows === null && $columns === null) { return $input; } $inputArray = []; foreach ($input as $inputRow) { $inputArray[] = self::arrayValues($inputRow); } $outputArray1 = self::takeRows($inputArray, $rows); if (is_string($outputArray1)) { return $outputArray1; } $outputArray2 = self::transpose($outputArray1); $outputArray3 = self::takeRows($outputArray2, $columns); if (is_string($outputArray3)) { return $outputArray3; } return self::transpose($outputArray3); } /** * EXPAND. * * @param mixed $input expecting two-dimensional array * * @return mixed[]|string */ public static function expand(mixed $input, mixed $rows, mixed $columns = null, mixed $pad = '#N/A'): array|string { if (!is_array($input)) { $input = [[$input]]; } if ($rows === null && $columns === null) { return $input; } $numRows = count($input); $rows ??= $numRows; if (!is_numeric($rows)) { return ExcelError::VALUE(); } $rows = (int) $rows; if ($rows < count($input)) { return ExcelError::VALUE(); } $numCols = 0; foreach ($input as $inputRow) { $numCols = max($numCols, is_array($inputRow) ? count($inputRow) : 1); } $columns ??= $numCols; if (!is_numeric($columns)) { return ExcelError::VALUE(); } $columns = (int) $columns; if ($columns < $numCols) { return ExcelError::VALUE(); } $inputArray = []; foreach ($input as $inputRow) { $inputArray[] = array_pad(self::arrayValues($inputRow), $columns, $pad); } $outputArray = []; $padRow = array_pad([], $columns, $pad); for ($count = 0; $count < $rows; ++$count) { $outputArray[] = ($count >= $numRows) ? $padRow : $inputArray[$count]; } return $outputArray; } }