Browse Source

Fix tests, spread operator and support for arrays with arbitrary keys

Alexandros Solanos 9 years ago
parent
commit
353d52a031
2 changed files with 81 additions and 11 deletions
  1. 25 10
      src/Collection/CollectionTrait.php
  2. 56 1
      tests/TestCase/Collection/CollectionTest.php

+ 25 - 10
src/Collection/CollectionTrait.php

@@ -692,23 +692,38 @@ trait CollectionTrait
             return new Collection([]);
         }
 
+        // contains each array of the collection
+        $values = [];
+        // contains the keys of each array
+        $valuesKeys = [];
+        // contains the number of elements of each array
+        $counts = [];
+
+        foreach ($this as $value) {
+            // fail if any of the values is a multidimensional array
+            if (count($value) !== count($value, COUNT_RECURSIVE)) {
+                throw new LogicException('Cannot find the cartesian product of a multidimensional array');
+            }
+
+            $valuesKeys[] = array_keys($value);
+            $counts[] = count($value);
+            $values[] = $value;
+        }
+
         $result = [];
-        $counts = $this->map(function ($arr) {
-            return count($arr);
-        })->toList();
-        $allArr = $this->toList();
-        $lastIndex = count($allArr) - 1;
+        $lastIndex = count($values) - 1;
         // holds the indexes of the arrays that generate the current combination
         $currentIndexes = array_fill(0, $lastIndex + 1, 0);
+
         $changeIndex = $lastIndex;
 
         while (!($changeIndex === 0 && $currentIndexes[0] === $counts[0])) {
-            $currentCombination = array_map(function ($arr, $index) {
-                return $arr[$index];
-            }, $allArr, $currentIndexes);
+            $currentCombination = array_map(function ($value, $keys, $index) {
+                return $value[$keys[$index]];
+            }, $values, $valuesKeys, $currentIndexes);
 
-            if ($filter === null || $filter(...$currentCombination)) {
-                $result[] = ($operation === null) ? $currentCombination : $operation(...$currentCombination);
+            if ($filter === null || call_user_func_array($filter, $currentCombination)) {
+                $result[] = ($operation === null) ? $currentCombination : call_user_func_array($operation, $currentCombination);
             }
 
             $currentIndexes[$lastIndex]++;

+ 56 - 1
tests/TestCase/Collection/CollectionTest.php

@@ -1777,6 +1777,14 @@ class CollectionTest extends TestCase
      */
     public function testCartesianProduct()
     {
+        $collection = new Collection([]);
+
+        $result = $collection->cartesianProduct();
+
+        $expected = [];
+
+        $this->assertEquals($expected, $result->toList());
+
         $collection = new Collection([['A', 'B', 'C'], [1, 2, 3]]);
 
         $result = $collection->cartesianProduct();
@@ -1858,10 +1866,57 @@ class CollectionTest extends TestCase
             [4 => ['B' => 'name']],
             [4 => ['B' => 'telephone']],
             [4 => ['C' => 'name']],
-            [4 => ['C' => 'telephone']]
+            [4 => ['C' => 'telephone']],
+        ];
+
+        $this->assertEquals($expected, $result->toList());
+
+        $collection = new Collection([
+            [
+                'name1' => 'alex',
+                'name2' => 'kostas',
+                0 => 'leon',
+            ],
+            [
+                'val1' => 'alex@example.com',
+                24 => 'kostas@example.com',
+                'val2' => 'leon@example.com',
+            ],
+        ]);
+
+        $result = $collection->cartesianProduct();
+
+        $expected = [
+            ['alex', 'alex@example.com'],
+            ['alex', 'kostas@example.com'],
+            ['alex', 'leon@example.com'],
+            ['kostas', 'alex@example.com'],
+            ['kostas', 'kostas@example.com'],
+            ['kostas', 'leon@example.com'],
+            ['leon', 'alex@example.com'],
+            ['leon', 'kostas@example.com'],
+            ['leon', 'leon@example.com'],
         ];
 
         $this->assertEquals($expected, $result->toList());
+
+        $this->expectException(\LogicException::class);
+
+        $collection = new Collection([
+            [
+                'names' => [
+                    'alex', 'kostas', 'leon'
+                ]
+            ],
+            [
+                'locations' => [
+                    'crete', 'london', 'paris'
+                ]
+            ],
+        ]);
+
+        $result = $collection->cartesianProduct();
+
     }
 
     public function testTranspose()