Skip to content

Commit df3a069

Browse files
authored
Merge pull request #4493 from oleibman/torow
TOCOL and TOROW
2 parents bd792ec + f3c3aba commit df3a069

File tree

11 files changed

+283
-10
lines changed

11 files changed

+283
-10
lines changed

docs/references/function-list-by-category.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@ RTD | **Not yet Implemented**
264264
SORT | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef\Sort::sort
265265
SORTBY | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef\Sort::sortBy
266266
TAKE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef\ChooseRowsEtc::take
267+
TOCOL | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef\TorowTocol::tocol
268+
TOROW | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef\TorowTocol::torow
267269
TRANSPOSE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef\Matrix::transpose
268270
UNIQUE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef\Unique::unique
269271
VLOOKUP | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef\VLookup::lookup
@@ -358,8 +360,6 @@ SUMX2PY2 | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig\SumSqu
358360
SUMXMY2 | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig\SumSquares::sumXMinusYSquared
359361
TAN | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Trig\Tangent::tan
360362
TANH | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Trig\Tangent::tanh
361-
TOCOL | **Not yet Implemented**
362-
TOROW | **Not yet Implemented**
363363
TRUNC | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Trunc::evaluate
364364
WRAPCOLS | **Not yet Implemented**
365365
WRAPROWS | **Not yet Implemented**

docs/references/function-list-by-name-compact.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -583,9 +583,9 @@ THAIYEAR | DATE_AND_TIME | **Not yet Implemented**
583583
TIME | DATE_AND_TIME | DateTimeExcel\Time::fromHMS
584584
TIMEVALUE | DATE_AND_TIME | DateTimeExcel\TimeValue::fromString
585585
TINV | STATISTICAL | Statistical\Distributions\StudentT::inverse
586-
TOCOL | MATH_AND_TRIG | **Not yet Implemented**
586+
TOCOL | LOOKUP_AND_REFERENCE | LookupRef\TorowTocol::tocol
587587
TODAY | DATE_AND_TIME | DateTimeExcel\Current::today
588-
TOROW | MATH_AND_TRIG | **Not yet Implemented**
588+
TOROW | LOOKUP_AND_REFERENCE | LookupRef\TorowTocol::torow
589589
TRANSPOSE | LOOKUP_AND_REFERENCE | LookupRef\Matrix::transpose
590590
TREND | STATISTICAL | Statistical\Trends::TREND
591591
TRIM | TEXT_AND_DATA | TextData\Trim::spaces

docs/references/function-list-by-name.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -579,9 +579,9 @@ THAIYEAR | CATEGORY_DATE_AND_TIME | **Not yet Implemente
579579
TIME | CATEGORY_DATE_AND_TIME | \PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\Time::fromHMS
580580
TIMEVALUE | CATEGORY_DATE_AND_TIME | \PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\TimeValue::fromString
581581
TINV | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions\StudentT::inverse
582-
TOCOL | CATEGORY_MATH_AND_TRIG | **Not yet Implemented**
582+
TOCOL | CATEGORY_LOOKUP_AND_REFERENCE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef\TorowTocol::tocol
583583
TODAY | CATEGORY_DATE_AND_TIME | \PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\Current::today
584-
TOROW | CATEGORY_MATH_AND_TRIG | **Not yet Implemented**
584+
TOROW | CATEGORY_LOOKUP_AND_REFERENCE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef\TorowTocol::torow
585585
TRANSPOSE | CATEGORY_LOOKUP_AND_REFERENCE | \PhpOffice\PhpSpreadsheet\Calculation\LookupRef\Matrix::transpose
586586
TREND | CATEGORY_STATISTICAL | \PhpOffice\PhpSpreadsheet\Calculation\Statistical\Trends::TREND
587587
TRIM | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet\Calculation\TextData\Trim::spaces

src/PhpSpreadsheet/Calculation/FunctionArray.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2439,13 +2439,13 @@ class FunctionArray extends CalculationBase
24392439
'argumentCount' => '0',
24402440
],
24412441
'TOCOL' => [
2442-
'category' => Category::CATEGORY_MATH_AND_TRIG,
2443-
'functionCall' => [Functions::class, 'DUMMY'],
2442+
'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE,
2443+
'functionCall' => [LookupRef\TorowTocol::class, 'tocol'],
24442444
'argumentCount' => '1-3',
24452445
],
24462446
'TOROW' => [
2447-
'category' => Category::CATEGORY_MATH_AND_TRIG,
2448-
'functionCall' => [Functions::class, 'DUMMY'],
2447+
'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE,
2448+
'functionCall' => [LookupRef\TorowTocol::class, 'torow'],
24492449
'argumentCount' => '1-3',
24502450
],
24512451
'TRANSPOSE' => [

src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ public static function transpose($matrixData): array
4444
if (!is_array($matrixData)) {
4545
$matrixData = [[$matrixData]];
4646
}
47+
if (!is_array(end($matrixData))) {
48+
$matrixData = [$matrixData];
49+
}
4750

4851
$column = 0;
4952
/** @var mixed[][] $matrixData */
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?php
2+
3+
namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
4+
5+
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
6+
use PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue;
7+
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
8+
9+
class TorowTocol
10+
{
11+
/**
12+
* Excel function TOCOL.
13+
*
14+
* @return mixed[]|string
15+
*/
16+
public static function tocol(mixed $array, mixed $ignore = 0, mixed $byColumn = false): array|string
17+
{
18+
$result = self::torow($array, $ignore, $byColumn);
19+
if (is_array($result)) {
20+
return array_map((fn ($x) => [$x]), $result);
21+
}
22+
23+
return $result;
24+
}
25+
26+
/**
27+
* Excel function TOROW.
28+
*
29+
* @return mixed[]|string
30+
*/
31+
public static function torow(mixed $array, mixed $ignore = 0, mixed $byColumn = false): array|string
32+
{
33+
if (!is_numeric($ignore)) {
34+
return ExcelError::VALUE();
35+
}
36+
$ignore = (int) $ignore;
37+
if ($ignore < 0 || $ignore > 3) {
38+
return ExcelError::VALUE();
39+
}
40+
if (is_int($byColumn) || is_float($byColumn)) {
41+
$byColumn = (bool) $byColumn;
42+
}
43+
if (!is_bool($byColumn)) {
44+
return ExcelError::VALUE();
45+
}
46+
if (!is_array($array)) {
47+
$array = [$array];
48+
}
49+
if ($byColumn) {
50+
$temp = [];
51+
foreach ($array as $row) {
52+
if (!is_array($row)) {
53+
$row = [$row];
54+
}
55+
$temp[] = Functions::flattenArray($row);
56+
}
57+
$array = ChooseRowsEtc::transpose($temp);
58+
} else {
59+
$array = Functions::flattenArray($array);
60+
}
61+
62+
return self::byRow($array, $ignore);
63+
}
64+
65+
/**
66+
* @param mixed[] $array
67+
*
68+
* @return mixed[]
69+
*/
70+
private static function byRow(array $array, int $ignore): array
71+
{
72+
$returnMatrix = [];
73+
foreach ($array as $row) {
74+
if (!is_array($row)) {
75+
$row = [$row];
76+
}
77+
foreach ($row as $cell) {
78+
if ($cell === null) {
79+
if ($ignore === 1 || $ignore === 3) {
80+
continue;
81+
}
82+
$cell = 0;
83+
} elseif (ErrorValue::isError($cell)) {
84+
if ($ignore === 2 || $ignore === 3) {
85+
continue;
86+
}
87+
}
88+
$returnMatrix[] = $cell;
89+
}
90+
}
91+
92+
return $returnMatrix;
93+
}
94+
}

tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/AllSetupTeardown.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,13 @@ protected function setArrayAsValue(): void
9595
Calculation::RETURN_ARRAY_AS_VALUE
9696
);
9797
}
98+
99+
protected function setArrayAsArray(): void
100+
{
101+
$spreadsheet = $this->getSpreadsheet();
102+
$calculation = Calculation::getInstance($spreadsheet);
103+
$calculation->setInstanceArrayReturnType(
104+
Calculation::RETURN_ARRAY_AS_ARRAY
105+
);
106+
}
98107
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\LookupRef;
6+
7+
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
10+
class TocolTest extends AllSetupTeardown
11+
{
12+
#[DataProvider('providerTocol')]
13+
public function testTorow(mixed $expectedResult, mixed $ignore = 'omitted', mixed $byColumn = 'omitted'): void
14+
{
15+
$this->mightHaveException($expectedResult);
16+
$sheet = $this->getSheet();
17+
$this->setArrayAsArray();
18+
if (is_string($ignore) && $ignore !== 'omitted') {
19+
$ignore = '"' . $ignore . '"';
20+
}
21+
if (is_string($byColumn) && $byColumn !== 'omitted') {
22+
$byColumn = '"' . $byColumn . '"';
23+
}
24+
$ignore = StringHelper::convertToString($ignore);
25+
$byColumn = StringHelper::convertToString($byColumn, convertBool: true);
26+
if ($ignore === 'omitted') {
27+
$formula = '=TOCOL(A1:D3)';
28+
} elseif ($byColumn === 'omitted') {
29+
$formula = "=TOCOL(A1:D3,$ignore)";
30+
} else {
31+
$formula = "=TOCOL(A1:D3,$ignore,$byColumn)";
32+
}
33+
34+
$data = [
35+
['a-one', 'b-one', 'c-one', 'd-one'],
36+
[null, 'b-two', 'c-two', '=2/0'],
37+
[' ', 'b-three', 'c-three', 'd-three'],
38+
];
39+
$sheet->fromArray($data, null, 'A1', true);
40+
$sheet->setCellValue('A5', $formula);
41+
$result = $sheet->getCell('A5')->getCalculatedValue();
42+
self::assertSame($expectedResult, $result);
43+
}
44+
45+
public static function providerTocol(): array
46+
{
47+
return [
48+
'defaults' => [[['a-one'], ['b-one'], ['c-one'], ['d-one'], [0], ['b-two'], ['c-two'], ['#DIV/0!'], [' '], ['b-three'], ['c-three'], ['d-three']]],
49+
'ignore=0' => [[['a-one'], ['b-one'], ['c-one'], ['d-one'], [0], ['b-two'], ['c-two'], ['#DIV/0!'], [' '], ['b-three'], ['c-three'], ['d-three']], 0],
50+
'ignore=1 supplied as 1.1' => [[['a-one'], ['b-one'], ['c-one'], ['d-one'], ['b-two'], ['c-two'], ['#DIV/0!'], [' '], ['b-three'], ['c-three'], ['d-three']], 1.1],
51+
'ignore=2' => [[['a-one'], ['b-one'], ['c-one'], ['d-one'], [0], ['b-two'], ['c-two'], [' '], ['b-three'], ['c-three'], ['d-three']], 2],
52+
'ignore=3' => [[['a-one'], ['b-one'], ['c-one'], ['d-one'], ['b-two'], ['c-two'], [' '], ['b-three'], ['c-three'], ['d-three']], 3],
53+
'ignore=4 invalid' => ['#VALUE!', 4],
54+
'ignore=string invalid' => ['#VALUE!', 'x'],
55+
'by column' => [[['a-one'], [0], [' '], ['b-one'], ['b-two'], ['b-three'], ['c-one'], ['c-two'], ['c-three'], ['d-one'], ['#DIV/0!'], ['d-three']], 0, true],
56+
'by column using float rather than bool, ignore=2' => [[['a-one'], [0], [' '], ['b-one'], ['b-two'], ['b-three'], ['c-one'], ['c-two'], ['c-three'], ['d-one'], ['d-three']], 2, 29.7],
57+
];
58+
}
59+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\LookupRef;
6+
7+
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
10+
class TorowTest extends AllSetupTeardown
11+
{
12+
#[DataProvider('providerTorow')]
13+
public function testTorow(mixed $expectedResult, mixed $ignore = 'omitted', mixed $byColumn = 'omitted'): void
14+
{
15+
$this->mightHaveException($expectedResult);
16+
$sheet = $this->getSheet();
17+
$this->setArrayAsArray();
18+
if (is_string($ignore) && $ignore !== 'omitted') {
19+
$ignore = '"' . $ignore . '"';
20+
}
21+
if (is_string($byColumn) && $byColumn !== 'omitted') {
22+
$byColumn = '"' . $byColumn . '"';
23+
}
24+
$ignore = StringHelper::convertToString($ignore);
25+
$byColumn = StringHelper::convertToString($byColumn, convertBool: true);
26+
if ($ignore === 'omitted') {
27+
$formula = '=TOROW(A1:D3)';
28+
} elseif ($byColumn === 'omitted') {
29+
$formula = "=TOROW(A1:D3,$ignore)";
30+
} else {
31+
$formula = "=TOROW(A1:D3,$ignore,$byColumn)";
32+
}
33+
34+
$data = [
35+
['a-one', 'b-one', 'c-one', 'd-one'],
36+
[null, 'b-two', 'c-two', '=2/0'],
37+
[' ', 'b-three', 'c-three', 'd-three'],
38+
];
39+
$sheet->fromArray($data, null, 'A1', true);
40+
$sheet->setCellValue('A5', $formula);
41+
$result = $sheet->getCell('A5')->getCalculatedValue();
42+
self::assertSame($expectedResult, $result);
43+
}
44+
45+
public static function providerTorow(): array
46+
{
47+
return [
48+
'defaults' => [['a-one', 'b-one', 'c-one', 'd-one', 0, 'b-two', 'c-two', '#DIV/0!', ' ', 'b-three', 'c-three', 'd-three']],
49+
'ignore=0' => [['a-one', 'b-one', 'c-one', 'd-one', 0, 'b-two', 'c-two', '#DIV/0!', ' ', 'b-three', 'c-three', 'd-three'], 0],
50+
'ignore=1 supplied as 1.1' => [['a-one', 'b-one', 'c-one', 'd-one', 'b-two', 'c-two', '#DIV/0!', ' ', 'b-three', 'c-three', 'd-three'], 1.1],
51+
'ignore=2' => [['a-one', 'b-one', 'c-one', 'd-one', 0, 'b-two', 'c-two', ' ', 'b-three', 'c-three', 'd-three'], 2],
52+
'ignore=3' => [['a-one', 'b-one', 'c-one', 'd-one', 'b-two', 'c-two', ' ', 'b-three', 'c-three', 'd-three'], 3],
53+
'ignore=-1 invalid' => ['#VALUE!', -1],
54+
'ignore=string invalid' => ['#VALUE!', 'x'],
55+
'by column' => [['a-one', 0, ' ', 'b-one', 'b-two', 'b-three', 'c-one', 'c-two', 'c-three', 'd-one', '#DIV/0!', 'd-three'], 0, true],
56+
'by column using int rather than bool, ignore=1' => [['a-one', ' ', 'b-one', 'b-two', 'b-three', 'c-one', 'c-two', 'c-three', 'd-one', '#DIV/0!', 'd-three'], 1, -15],
57+
];
58+
}
59+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\LookupRef;
6+
7+
use PHPUnit\Framework\Attributes\DataProvider;
8+
9+
class TransposeOnSpreadsheetTest extends AllSetupTeardown
10+
{
11+
#[DataProvider('providerTRANSPOSE')]
12+
public function testTRANSPOSE(mixed $expectedResult, mixed $matrix): void
13+
{
14+
$sheet = $this->getSheet();
15+
$this->setArrayAsArray();
16+
if (!is_array($matrix)) {
17+
$matrix = [$matrix];
18+
}
19+
$sheet->fromArray($matrix, null, 'A1', true);
20+
$highColumn = $sheet->getHighestDataColumn();
21+
$highRow = $sheet->getHighestDataRow();
22+
$newHighColumn = $highColumn;
23+
++$newHighColumn;
24+
$sheet->getCell("{$newHighColumn}1")
25+
->setValue("=TRANSPOSE(A1:$highColumn$highRow)");
26+
self::assertSame($expectedResult, $sheet->getCell("{$newHighColumn}1")->getCalculatedValue());
27+
}
28+
29+
public static function providerTRANSPOSE(): array
30+
{
31+
return require 'tests/data/Calculation/LookupRef/TRANSPOSE.php';
32+
}
33+
}

0 commit comments

Comments
 (0)