diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index 30b2aaec849a..77d19aeea3ed 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -80,6 +80,67 @@ public function average($key = null) return $this->avg($key); } + /** + * Get the median of a given key. + * + * @param null $key + * @return mixed|null + */ + public function median($key = null) + { + $count = $this->count(); + if ($count == 0) { + return; + } + + $collection = isset($key) ? $this->map(function ($value) use ($key) { + return $value->{$key}; + }) : $this; + + $values = $collection->values()->sort(); + $middlePosition = (int) floor($count / 2); + $hasAnOddQuantity = $count % 2; + + if ($hasAnOddQuantity) { + return $values->get($middlePosition); + } + + $start = $values->get($middlePosition - 1); + $end = $values->get($middlePosition); + + return (new static([$start, $end]))->average(); + } + + /** + * Get the mode of a given key. + * + * @param null $key + * @return static|null + */ + public function mode($key = null) + { + $count = $this->count(); + if ($count == 0) { + return; + } + + $collection = isset($key) ? $this->map(function ($value) use ($key) { + return $value->{$key}; + }) : $this; + + $set = new static; + $collection->each(function ($value) use (&$set) { + $set[$value] = isset($set[$value]) ? $set[$value] + 1 : 1; + }); + + $sorted = $set->sort(); + $highestValue = $sorted->last(); + + return $sorted->filter(function ($value) use ($highestValue) { + return $value == $highestValue; + })->sort()->keys(); + } + /** * Collapse the collection of items into a single array. * diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 2b12ae21e1df..8a91eea741e4 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -1282,6 +1282,68 @@ public function testPipe() return $collection->sum(); })); } + + public function testMedianValueWithArrayCollection() + { + $collection = new Collection([1, 2, 2, 4]); + + $this->assertEquals(2, $collection->median()); + } + + public function testMedianValueByKey() + { + $collection = new Collection([ + (object) ['foo' => 1], + (object) ['foo' => 2], + (object) ['foo' => 2], + (object) ['foo' => 4], + ]); + $this->assertEquals(2, $collection->median('foo')); + } + + public function testEvenMedianCollection() + { + $collection = new Collection([ + (object) ['foo' => 0], + (object) ['foo' => 3], + ]); + $this->assertEquals(1.5, $collection->median('foo')); + } + + public function testMedianOnEmptyCollectionReturnsNull() + { + $collection = new Collection(); + $this->assertNull($collection->median()); + } + + public function testModeOnNullCollection() + { + $collection = new Collection(); + $this->assertNull($collection->mode()); + } + + public function testMode() + { + $collection = new Collection([1, 2, 3, 4, 4, 5]); + $this->assertEquals(new Collection([4]), $collection->mode()); + } + + public function testModeValueByKey() + { + $collection = new Collection([ + (object) ['foo' => 1], + (object) ['foo' => 1], + (object) ['foo' => 2], + (object) ['foo' => 4], + ]); + $this->assertEquals(new Collection([1]), $collection->mode('foo')); + } + + public function testWithMultipleModeValues() + { + $collection = new Collection([1, 2, 2, 1]); + $this->assertEquals(new Collection([1, 2]), $collection->mode()); + } } class TestAccessorEloquentTestStub