Browse Source

Merge pull request #5719 from ankr/3.0-collection-reduce-optional-initial

Initial value for Collection::reduce is now optional
Mark Story 11 years ago
parent
commit
1da49c11cd

+ 3 - 1
src/Collection/CollectionInterface.php

@@ -179,12 +179,14 @@ interface CollectionInterface extends Iterator, JsonSerializable
      * applying the callback function to all elements. $zero is the initial state
      * of the reduction, and each successive step of it should be returned
      * by the callback function.
+     * If $zero is omitted the first value of the collection will be used in its place
+     * and reduction will start from the second item.
      *
      * @param callable $c The callback function to be called
      * @param mixed $zero The state of reduction
      * @return void
      */
-    public function reduce(callable $c, $zero);
+    public function reduce(callable $c, $zero = null);
 
     /**
      * Returns a new collection containing the column or property value found in each

+ 11 - 1
src/Collection/CollectionTrait.php

@@ -135,10 +135,20 @@ trait CollectionTrait
      * {@inheritDoc}
      *
      */
-    public function reduce(callable $c, $zero)
+    public function reduce(callable $c, $zero = null)
     {
+        $isFirst = false;
+        if (func_num_args() < 2) {
+            $isFirst = true;
+        }
+
         $result = $zero;
         foreach ($this->_unwrap() as $k => $value) {
+            if ($isFirst) {
+                $result = $value;
+                $isFirst = false;
+                continue;
+            }
             $result = $c($result, $value, $k);
         }
         return $result;

+ 27 - 2
tests/TestCase/Collection/CollectionTest.php

@@ -252,11 +252,11 @@ class CollectionTest extends TestCase
     }
 
     /**
-     * Tests reduce
+     * Tests reduce with initial value
      *
      * @return void
      */
-    public function testReduce()
+    public function testReduceWithInitialValue()
     {
         $items = ['a' => 1, 'b' => 2, 'c' => 3];
         $collection = new Collection($items);
@@ -277,6 +277,31 @@ class CollectionTest extends TestCase
     }
 
     /**
+     * Tests reduce without initial value
+     *
+     * @return void
+     */
+    public function testReduceWithoutInitialValue()
+    {
+        $items = ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4];
+        $collection = new Collection($items);
+        $callable = $this->getMock('stdClass', ['__invoke']);
+        $callable->expects($this->at(0))
+            ->method('__invoke')
+            ->with(1, 2, 'b')
+            ->will($this->returnValue(3));
+        $callable->expects($this->at(1))
+            ->method('__invoke')
+            ->with(3, 3, 'c')
+            ->will($this->returnValue(6));
+        $callable->expects($this->at(2))
+            ->method('__invoke')
+            ->with(6, 4, 'd')
+            ->will($this->returnValue(10));
+        $this->assertEquals(10, $collection->reduce($callable));
+    }
+
+    /**
      * Tests extract
      *
      * @return void