diff --git a/README.md b/README.md index 1803287..3471a46 100644 --- a/README.md +++ b/README.md @@ -263,6 +263,7 @@ will return: toArray toJson toUrl +transform transpose traverse tree @@ -456,6 +457,7 @@ will return: * [suffix()](#suffix) : Adds a suffix to each map entry * [toJson()](#tojson) : Returns the elements in JSON format * [toUrl()](#tourl) : Creates a HTTP query string +* [transfrom()](#transfrom) : Applies a callback to each element which creates new key/value pairs * [transpose()](#transpose) : Exchanges rows and columns for a two dimensional map * [traverse()](#traverse) : Traverses trees of nested items passing each item to the callback * [trim()](#trim) : Removes the passed characters from the left/right of all strings @@ -3354,7 +3356,7 @@ Map::from( ["a b c", "cbxa"] )->ltrim( 'abc' ); ### map() -Calls the passed function once for each element and returns a new map for the result. +Maps new values to the existing keys using the passed function and returns a new map for the result. ```php public function map( callable $callback ) : self @@ -5388,6 +5390,44 @@ Map::from( ['a' => ['b' => 'abc', 'c' => 'def'], 'd' => 123] )->toUrl(); ``` +### transform() + +Creates new key/value pairs using the passed function and returns a new map for the result. + +```php +public function transform( \Closure $callback ) : self +``` + +* @param **\Closure** `$callback` Function with (value, key) parameters and returns an array of new key/value pair(s) +* @return **self<int|string,mixed>** New map with the new key/value pairs + +If a key is returned twice, the last value will overwrite previous values. + +**Examples:** + +```php +Map::from( ['a' => 2, 'b' => 4] )->transform( function( $value, $key ) { + return [$key . '-2' => $value * 2]; +} ); +// ['a-2' => 4, 'b-2' => 8] + +Map::from( ['a' => 2, 'b' => 4] )->transform( function( $value, $key ) { + return [$key => $value * 2, $key . $key => $value * 4]; +} ); +// ['a' => 4, 'aa' => 8, 'b' => 8, 'bb' => 16] + +Map::from( ['a' => 2, 'b' => 4] )->transform( function( $value, $key ) { + return $key < 'b' ? [$key => $value * 2] : null; +} ); +// ['a' => 4] + +Map::from( ['la' => 2, 'le' => 4, 'li' => 6] )->transform( function( $value, $key ) { + return [$key[0] => $value * 2]; +} ); +// ['l' => 12] +``` + + ### transpose() Exchanges rows and columns for a two dimensional map. diff --git a/src/Map.php b/src/Map.php index 9d031e6..f328d6d 100644 --- a/src/Map.php +++ b/src/Map.php @@ -2850,7 +2850,7 @@ public function ltrim( string $chars = " \n\r\t\v\x00" ) : self /** - * Calls the passed function once for each element and returns a new map for the result. + * Maps new values to the existing keys using the passed function and returns a new map for the result. * * Examples: * Map::from( ['a' => 2, 'b' => 4] )->map( function( $value, $key ) { @@ -4909,6 +4909,49 @@ public function toUrl() : string } + /** + * Creates new key/value pairs using the passed function and returns a new map for the result. + * + * Examples: + * Map::from( ['a' => 2, 'b' => 4] )->transform( function( $value, $key ) { + * return [$key . '-2' => $value * 2]; + * } ); + * Map::from( ['a' => 2, 'b' => 4] )->transform( function( $value, $key ) { + * return [$key => $value * 2, $key . $key => $value * 4]; + * } ); + * Map::from( ['a' => 2, 'b' => 4] )->transform( function( $value, $key ) { + * return $key < 'b' ? [$key => $value * 2] : null; + * } ); + * Map::from( ['la' => 2, 'le' => 4, 'li' => 6] )->transform( function( $value, $key ) { + * return [$key[0] => $value * 2]; + * } ); + * + * Results: + * ['a-2' => 4, 'b-2' => 8] + * ['a' => 4, 'aa' => 8, 'b' => 8, 'bb' => 16] + * ['a' => 4] + * ['l' => 12] + * + * If a key is returned twice, the last value will overwrite previous values. + * + * @param \Closure $callback Function with (value, key) parameters and returns an array of new key/value pair(s) + * @return self New map with the new key/value pairs + */ + public function transform( \Closure $callback ) : self + { + $result = []; + + foreach( $this->list() as $key => $value ) + { + foreach( (array) $callback( $value, $key ) as $newkey => $newval ) { + $result[$newkey] = $newval; + } + } + + return new static( $result ); + } + + /** * Exchanges rows and columns for a two dimensional map. * diff --git a/tests/MapTest.php b/tests/MapTest.php index a19fc66..74dc80f 100644 --- a/tests/MapTest.php +++ b/tests/MapTest.php @@ -3204,6 +3204,50 @@ public function testTimesObjects() } + public function testTransform() + { + $m = Map::from( ['a' => 2, 'b' => 4] )->transform( function( $value, $key ) { + return [$key . '-2' => $value * 2]; + } ); + + $this->assertInstanceOf( Map::class, $m ); + $this->assertSame( ['a-2' => 4, 'b-2' => 8], $m->toArray() ); + } + + + public function testTransformExtend() + { + $m = Map::from( ['a' => 2, 'b' => 4] )->transform( function( $value, $key ) { + return [$key => $value * 2, $key . $key => $value * 4]; + } ); + + $this->assertInstanceOf( Map::class, $m ); + $this->assertSame( ['a' => 4, 'aa' => 8, 'b' => 8, 'bb' => 16], $m->toArray() ); + } + + + public function testTransformShorten() + { + $m = Map::from( ['a' => 2, 'b' => 4] )->transform( function( $value, $key ) { + return $key < 'b' ? [$key => $value * 2] : null; + } ); + + $this->assertInstanceOf( Map::class, $m ); + $this->assertSame( ['a' => 4], $m->toArray() ); + } + + + public function testTransformOverwrite() + { + $m = Map::from( ['la' => 2, 'le' => 4, 'li' => 6] )->transform( function( $value, $key ) { + return [$key[0] => $value * 2]; + } ); + + $this->assertInstanceOf( Map::class, $m ); + $this->assertSame( ['l' => 12], $m->toArray() ); + } + + public function testTranspose() { $m = Map::from( [