Skip to content

Commit

Permalink
Allow closure for avg() method and changes NULL handling
Browse files Browse the repository at this point in the history
  • Loading branch information
aimeos committed Jul 30, 2024
1 parent 704b2b8 commit 53c2e00
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 12 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -803,10 +803,10 @@ Map::from( [1, 3, 5] )->at( 3 );
Returns the average of all integer and float values in the map.

```php
public function avg( string $key = null ) : float
public function avg( string $col = null ) : float
```

* @param **string|null** `$key` Key or path to the values in the nested array or object to compute the average for
* @param **Closure|string|null** `$col` Closure, key or path to the values in the nested array or object to compute the average for
* @return **float** Average of all elements or 0 if there are no elements in the map

This does also work for multi-dimensional arrays by passing the keys
Expand All @@ -821,7 +821,7 @@ Map::from( [1, 3, 5] )->avg();
// 3

Map::from( [1, null, 5] )->avg();
// 2
// 3

Map::from( [1, 'sum', 5] )->avg();
// 2
Expand All @@ -831,6 +831,9 @@ Map::from( [['p' => 30], ['p' => 50], ['p' => 10]] )->avg( 'p' );

Map::from( [['i' => ['p' => 30]], ['i' => ['p' => 50]]] )->avg( 'i/p' );
// 40

Map::from( [30, 50, 10] )->avg( fn( $val, $key ) => $val < 50 ? $val : null );
// 20
```


Expand Down
25 changes: 17 additions & 8 deletions src/Map.php
Original file line number Diff line number Diff line change
Expand Up @@ -520,25 +520,34 @@ public function at( int $pos )
* Map::from( [1, 'sum', 5] )->avg();
* Map::from( [['p' => 30], ['p' => 50], ['p' => 10]] )->avg( 'p' );
* Map::from( [['i' => ['p' => 30]], ['i' => ['p' => 50]]] )->avg( 'i/p' );
* Map::from( [30, 50, 10] )->avg( fn( $val, $key ) => $val < 50 ? $val : null );
*
* Results:
* The first line will return "3", the second and third one "2", the forth
* one "30" and the last one "40".
* The first and second line will return "3", the third one "2", the forth
* one "30", the fifth one "40" and the last one "20".
*
* NULL values are treated as 0, non-numeric values will generate an error.
* NULL values are ignored, non-numeric values will generate an error.
*
* This does also work for multi-dimensional arrays by passing the keys
* of the arrays separated by the delimiter ("/" by default), e.g. "key1/key2/key3"
* to get "val" from ['key1' => ['key2' => ['key3' => 'val']]]. The same applies to
* public properties of objects or objects implementing __isset() and __get() methods.
*
* @param string|null $key Key or path to the values in the nested array or object to compute the average for
* @param Closure|string|null $col Closure, key or path to the values in the nested array or object to compute the average for
* @return float Average of all elements or 0 if there are no elements in the map
*/
public function avg( string $key = null ) : float
public function avg( $col = null ) : float
{
$cnt = count( $this->list() );
return $cnt > 0 ? $this->sum( $key ) / $cnt : 0;
if( $col instanceof \Closure ) {
$vals = array_map( $col, array_values( $this->list() ), array_keys( $this->list() ) );
} else {
$vals = $col !== null ? $this->col( $col )->toArray() : $this->list();
}

$vals = array_filter( $vals, fn( $val ) => $val !== null );
$cnt = count( $vals );

return $cnt > 0 ? array_sum( $vals ) / $cnt : 0;
}


Expand Down Expand Up @@ -4682,7 +4691,7 @@ public function sum( $col = null ) : float
$vals = $col !== null ? $this->col( $col )->toArray() : $this->list();
}

return !empty( $vals ) ? array_sum( $vals ) : 0;
return array_sum( $vals );
}


Expand Down
9 changes: 8 additions & 1 deletion tests/MapTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,18 @@ public function testAt()
public function testAvg()
{
$this->assertSame( 3.0, Map::from( [1, 3, 5] )->avg() );
$this->assertSame( 2.0, Map::from( [1, null, 5] )->avg() );
$this->assertSame( 3.0, Map::from( [1, null, 5] )->avg() );
$this->assertSame( 2.0, Map::from( [1, 0.0, 5] )->avg() );
}


public function testAvgClosure()
{
$this->assertSame( 20.0, Map::from( [30, 50, 10] )->avg( fn( $val ) => $val < 50 ? $val : null ) );
$this->assertSame( 30.0, Map::from( [30, 50, 10] )->avg( fn( $val, $key ) => $key < 1 ? $val : null ) );
}


public function testAvgPath()
{
$this->assertSame( 30.0, Map::from( [['p' => 30], ['p' => 50], ['p' => 10]] )->avg( 'p' ) );
Expand Down

0 comments on commit 53c2e00

Please sign in to comment.