Skip to content

Commit

Permalink
Add avg and median methods to CollectionTrait and Interface
Browse files Browse the repository at this point in the history
  • Loading branch information
Iandenh committed Jul 18, 2017
1 parent 341c6da commit f1bfd8b
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 0 deletions.
57 changes: 57 additions & 0 deletions src/Collection/CollectionInterface.php
Expand Up @@ -285,6 +285,63 @@ public function max($callback, $type = SORT_NUMERIC);
*/
public function min($callback, $type = SORT_NUMERIC);

/**
* Returns the average of all the values extracted with $matcher
* or of this collection.
*
* ### Example:
*
* ```
* $items = [
* ['invoice' => ['total' => 100]],
* ['invoice' => ['total' => 200]]
* ];
*
* $total = (new Collection($items))->avg('invoice.total');
*
* // Total: 150
*
* $total = (new Collection([1, 2, 3]))->avg();
* // Total: 2
* ```
*
* @param string|callable|null $matcher The property name to sum or a function
* If no value is passed, an identity function will be used.
* that will return the value of the property to sum.
* @return float|int|null
*/
public function avg($matcher = null);

/**
* Returns the median of all the values extracted with $matcher
* or of this collection.
*
* ### Example:
*
* ```
* $items = [
* ['invoice' => ['total' => 400]],
* ['invoice' => ['total' => 500]]
* ['invoice' => ['total' => 100]]
* ['invoice' => ['total' => 333]]
* ['invoice' => ['total' => 200]]
* ];
*
* $total = (new Collection($items))->median('invoice.total');
*
* // Total: 333
*
* $total = (new Collection([1, 2, 3, 4]))->median();
* // Total: 2.5
* ```
*
* @param string|callable|null $matcher The property name to sum or a function
* If no value is passed, an identity function will be used.
* that will return the value of the property to sum.
* @return float|int|null
*/
public function median($matcher = null);

/**
* Returns a sorted iterator out of the elements in this collection,
* ranked in ascending order by the results of running each value through a
Expand Down
48 changes: 48 additions & 0 deletions src/Collection/CollectionTrait.php
Expand Up @@ -190,6 +190,54 @@ public function min($callback, $type = SORT_NUMERIC)
return (new SortIterator($this->unwrap(), $callback, SORT_ASC, $type))->first();
}

/**
* {@inheritDoc}
*/
public function avg($matcher = null)
{
$iterator = $this->unwrap();
$count = $iterator instanceof Countable ?
count($iterator) :
iterator_count($iterator);

if ($count === 0) {
return null;
}

return $this->sumOf($matcher) / $count;
}

/**
* {@inheritDoc}
*/
public function median($matcher = null)
{
$iterator = $this->unwrap();
$count = $iterator instanceof Countable ?
count($iterator) :
iterator_count($iterator);

if ($count === 0) {
return null;
}

$middle = (int)($count / 2);
$elements = $this;
if ($matcher != null) {
$elements = $elements->extract($matcher);
}
$values = $elements->toArray();
sort($values);

if ($count % 2) {
return $values[$middle];
}

return (new static([
$values[$middle - 1], $values[$middle],
]))->avg();
}

/**
* {@inheritDoc}
*/
Expand Down
54 changes: 54 additions & 0 deletions tests/TestCase/Collection/CollectionTest.php
Expand Up @@ -59,6 +59,60 @@ public function testArrayIsWrapped()
$this->assertEquals($items, iterator_to_array($collection));
}

/**
* Tests that it is possible to convert an array into a collection
*
* @return void
*/
public function testAvg()
{
$items = [1, 2, 3];
$collection = new Collection($items);
$this->assertEquals(2, $collection->avg());

$collection = new Collection([]);
$this->assertNull($collection->avg());

$items = [['foo' => 1], ['foo' => 2], ['foo' => 3]];
$collection = new Collection($items);
$this->assertEquals(2, $collection->avg('foo'));
$items = [
['invoice' => ['total' => 100]],
['invoice' => ['total' => 200]]
];

$this->assertEquals(150, (new Collection($items))->avg('invoice.total'));
}

/**
* Tests that it is possible to convert an array into a collection
*
* @return void
*/
public function testMedian()
{
$items = [5, 2, 4];
$collection = new Collection($items);
$this->assertEquals(4, $collection->median());

$collection = new Collection([]);
$this->assertNull($collection->median());

$items = [1, 2, 3, 4];
$collection = new Collection($items);
$this->assertEquals(2.5, $collection->median());

$items = [
['invoice' => ['total' => 400]],
['invoice' => ['total' => 500]],
['invoice' => ['total' => 200]],
['invoice' => ['total' => 100]],
['invoice' => ['total' => 333]]
];

$this->assertEquals(333, (new Collection($items))->median('invoice.total'));
}

/**
* Tests that it is possible to convert an iterator into a collection
*
Expand Down

0 comments on commit f1bfd8b

Please sign in to comment.