diff --git a/README.md b/README.md
index 1803287..741e16b 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ Supported PHP versions:
* [Add](#add)
* [Aggregate](#aggregate)
* [Debug](#debug)
- * [Order](#orderby)
+ * [Order](#order-by)
* [Shorten](#shorten)
* [Test](#test)
* [Transform](#transform)
@@ -231,6 +231,7 @@ will return:
remove
replace
reverse
+reversed
rsort
rtrim
search
@@ -238,10 +239,12 @@ will return:
set
shift
shuffle
+shuffled
skip
slice
some
sort
+sorted
splice
split
strAfter
@@ -262,7 +265,10 @@ will return:
times
toArray
toJson
+toReversed
+toSorted
toUrl
+transform
transpose
traverse
tree
@@ -330,9 +336,9 @@ will return:
* [insertBefore()](#insertbefore) : Inserts the value before the given element
* [merge()](#merge) : Combines elements overwriting existing ones
* [pad()](#pad) : Fill up to the specified length with the given value
-* [prepend()](#prepend) : Adds an element at the beginning
+* [prepend()](#prepend) : Adds an element at the beginning (alias)
* [push()](#push) : Adds an element to the end
-* [put()](#put) : Sets the given key and value in the map
+* [put()](#put) : Sets the given key and value in the map (alias)
* [set()](#set) : Overwrites or adds an element
* [union()](#union) : Adds the elements without overwriting existing ones
* [unshift()](#unshift) : Adds an element at the beginning
@@ -354,7 +360,7 @@ will return:
* [dump()](#dump) : Prints the map content
* [tap()](#tap) : Passes a clone of the map to the given callback
-### OrderBy
+### Order By
* [arsort()](#arsort) : Reverse sort elements preserving keys
* [asort()](#asort) : Sort elements preserving keys
@@ -362,9 +368,14 @@ will return:
* [ksort()](#ksort) : Sort elements by keys
* [order()](#order) : Orders elements by the passed keys
* [reverse()](#reverse) : Reverses the array order preserving keys
+* [reversed()](#reversed) : Reverses the element order in a copy of the map
+* [toReversed()](#toreversed) : Reverses the element order in a copy of the map (alias)
* [rsort()](#rsort) : Reverse sort elements using new keys
* [shuffle()](#shuffle) : Randomizes the element order
-* [sort()](#sort) : Sorts the elements assigning new keys
+* [shuffled()](#shuffled) : Randomizes the element order in a copy of the map
+* [sort()](#sort) : Sorts the elements in-place assigning new keys
+* [sorted()](#sorted) : Sorts the elements in a copy of the map using new keys
+* [toSorted()](#tosorted) : Sorts the elements in a copy of the map using new keys (alias)
* [uasort()](#uasort) : Sorts elements preserving keys using callback
* [uksort()](#uksort) : Sorts elements by keys using callback
* [usort()](#usort) : Sorts elements using callback assigning new keys
@@ -442,7 +453,7 @@ will return:
* [map()](#map) : Applies a callback to each element and returns the results
* [partition()](#partition) : Breaks the list into the given number of groups
* [pipe()](#pipe) : Applies a callback to the whole map
-* [pluck()](#pluck) : Creates a key/value mapping
+* [pluck()](#pluck) : Creates a key/value mapping (alias)
* [prefix()](#prefix) : Adds a prefix to each map entry
* [reduce()](#reduce) : Computes a single value from the map content
* [rekey()](#rekey) : Changes the keys according to the passed function
@@ -456,6 +467,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
@@ -537,6 +549,11 @@ map( function() {
} );
```
+**See also:**
+
+* [rekey()](#rekey) - Changes the keys according to the passed function
+* [transform()](#transform) - Creates new key/value pairs using the passed function and returns a new map for the result
+
### __construct()
@@ -2523,7 +2540,7 @@ Map::from( ['1', '2'] )->in( 2, true );
### includes()
-Tests if the passed element or elements are part of the map.
+Tests if the passed element or elements are part of the map (alias).
```php
public function includes( $element, bool $strict = false ) : bool
@@ -2536,24 +2553,9 @@ public function includes( $element, bool $strict = false ) : bool
This method is an alias for [in()](#in). For performance reasons, `in()` should be preferred
because it uses one method call less than `includes()`.
-**Examples:**
-
-```php
-Map::from( ['a', 'b'] )->includes( 'a' );
-// true
-
-Map::from( ['a', 'b'] )->includes( ['a', 'b'] );
-// true
-
-Map::from( ['a', 'b'] )->includes( 'x' );
-// false
+**See also:**
-Map::from( ['a', 'b'] )->includes( ['a', 'x'] );
-// false
-
-Map::from( ['1', '2'] )->includes( 2, true );
-// false
-```
+* [in()](#in) - Underlying method with same parameters and return value but better performance
### index()
@@ -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
@@ -3861,7 +3863,7 @@ Map::from( ['a', 'b'] )->pipe( function( $map ) {
### pluck()
-Returns the values of a single column/property from an array of arrays or list of elements in a new map.
+Returns the values of a single column/property from an array of arrays or list of elements in a new map (alias).
```php
public function pluck( string $valuecol = null, string $indexcol = null ) : self
@@ -3874,6 +3876,9 @@ public function pluck( string $valuecol = null, string $indexcol = null ) : self
This method is an alias for [col()](#col). For performance reasons, `col()` should
be preferred because it uses one method call less than `pluck()`.
+**See also:**
+
+* [col()](#col) - Underlying method with same parameters and return value but better performance
### pop()
@@ -3956,7 +3961,7 @@ Map::from( ['a', 'b'] )->prefix( function( $item, $key ) {
### prepend()
-Pushes an element onto the beginning of the map without returning a new map.
+Pushes an element onto the beginning of the map without returning a new map (alias).
```php
public function prepend( $value, $key = null ) : self
@@ -3966,17 +3971,12 @@ public function prepend( $value, $key = null ) : self
* @param **int|string|null** `$key` Key for the item or NULL to reindex all numerical keys
* @return **self<int|string,mixed>** Updated map for fluid interface
-This method is an alias for the [unshift()](#unshift) method.
+This method is an alias for the [unshift()](#unshift) method. For performance reasons, `unshift()` should
+be preferred because it uses one method call less than `prepend()`.
-**Examples:**
+**See also:**
-```php
-Map::from( ['a', 'b'] )->prepend( 'd' );
-// ['d', 'a', 'b']
-
-Map::from( ['a', 'b'] )->prepend( 'd', 'first' );
-// ['first' => 'd', 0 => 'a', 1 => 'b']
-```
+* [unshift()](#unshift) - Underlying method with same parameters and return value but better performance
### pull()
@@ -4023,28 +4023,22 @@ Map::from( ['a', 'b'] )->push( 'aa' );
### put()
-Sets the given key and value in the map without returning a new map.
+Sets the given key and value in the map without returning a new map (alias).
```php
public function put( $key, $value ) : self
```
-This method is an alias for `set()`. For performance reasons, `set()` should be
-preferred because it uses one method call less than `put()`.
-
* @param **int|string** `$key` Key to set the new value for
* @param **mixed** `$value` New element that should be set
* @return **self<int|string,mixed>** Updated map for fluid interface
-**Examples:**
+This method is an alias for [set()](#set). For performance reasons, `set()` should be
+preferred because it uses one method call less than `put()`.
-```php
-Map::from( ['a'] )->put( 1, 'b' );
-// [0 => 'a', 1 => 'b']
+**See also:**
-Map::from( ['a'] )->put( 0, 'b' );
-// [0 => 'b']
-```
+* [set()](#set) - Underlying method with same parameters and return value but better performance
### random()
@@ -4155,6 +4149,11 @@ Map::from( ['a' => 2, 'b' => 4] )->rekey( function( $value, $key ) {
// ['key-a' => 2, 'key-b' => 4]
```
+**See also:**
+
+* [map()](#map) - Maps new values to the existing keys using the passed function and returns a new map for the result
+* [transform()](#transform) - Creates new key/value pairs using the passed function and returns a new map for the result
+
### remove()
@@ -4228,6 +4227,38 @@ Map::from( ['name' => 'test', 'last' => 'user'] )->reverse();
// ['last' => 'user', 'name' => 'test']
```
+**See also:**
+
+* [reversed()](#reversed) - Reverses the element order in a copy of the map
+
+
+### reversed()
+
+Reverses the element order in a copy of the map.
+
+```php
+public function reversed() : self
+```
+
+* @return **self<int|string,mixed>** New map with a reversed copy of the elements
+
+The keys are preserved using this method and a new map is created before reversing the elements.
+Thus, [reverse()](#reverse) should be preferred for performance reasons if possible.
+
+**Examples:**
+
+```php
+Map::from( ['a', 'b'] )->reversed();
+// ['b', 'a']
+
+Map::from( ['name' => 'test', 'last' => 'user'] )->reversed();
+// ['last' => 'user', 'name' => 'test']
+```
+
+**See also:**
+
+* [reverse()](#reverse) - Reverses the element order without returning a new map
+
### rsort()
@@ -4417,6 +4448,36 @@ Map::from( [2 => 'a', 4 => 'b'] )->shuffle( true );
// [2 => 'a', 4 => 'b'] in random order with keys preserved
```
+**See also:**
+
+* [shuffled()](#shuffled) - Shuffles the elements in a copy of the map.
+
+
+### shuffled()
+
+Shuffles the elements in a copy of the map.
+
+```php
+public function shuffled( bool $assoc = false ) : self
+```
+
+* @param **bool** `$assoc` True to preserve keys, false to assign new keys
+* @return **self<int|string,mixed>** New map with a shuffled copy of the elements
+
+**Examples:**
+
+```php
+Map::from( [2 => 'a', 4 => 'b'] )->shuffled();
+// ['a', 'b'] in random order with new keys
+
+Map::from( [2 => 'a', 4 => 'b'] )->shuffled( true );
+// [2 => 'a', 4 => 'b'] in random order with keys preserved
+```
+
+**See also:**
+
+* [shuffle()](#shuffle) - Shuffles the elements in the map without returning a new map
+
### skip()
@@ -4524,7 +4585,7 @@ Sorts all elements without maintaining the key association.
public function sort( int $options = SORT_REGULAR ) : self
```
-* @param **int** `$options` Sort options for `sort()`
+* @param **int** `$options` Sort options for PHP `sort()`
* @return **self<int|string,mixed>** Updated map for fluid interface
The parameter modifies how the values are compared. Possible parameter values are:
@@ -4548,6 +4609,43 @@ Map::from( [0 => 'b', 1 => 'a'] )->sort();
```
+### sorted()
+
+Sorts the elements in a copy of the map using new keys.
+
+```php
+public function sorted( int $options = SORT_REGULAR ) : self
+```
+
+* @param **int** `$options` Sort options for PHP `sort()`
+* @return **self<int|string,mixed>** New map with a sorted copy of the elements
+
+The parameter modifies how the values are compared. Possible parameter values are:
+- SORT_REGULAR : compare elements normally (don't change types)
+- SORT_NUMERIC : compare elements numerically
+- SORT_STRING : compare elements as strings
+- SORT_LOCALE_STRING : compare elements as strings, based on the current locale or changed by `setlocale()`
+- SORT_NATURAL : compare elements as strings using "natural ordering" like `natsort()`
+- SORT_FLAG_CASE : use SORT_STRING|SORT_FLAG_CASE and SORT_NATURAL|SORT_FLAG_CASE to sort strings case-insensitively
+
+The keys aren't preserved and elements get a new index and a new map is created before sorting the elements.
+Thus, [sort()](#sort) should be preferred for performance reasons if possible.
+
+**Examples:**
+
+```php
+Map::from( ['a' => 1, 'b' => 0] )->sorted();
+// [0 => 0, 1 => 1]
+
+Map::from( [0 => 'b', 1 => 'a'] )->sorted();
+// [0 => 'a', 1 => 'b']
+```
+
+**See also:**
+
+* [sort()](#sort) - Sorts elements in-place in the original map
+
+
### splice()
Removes a portion of the map and replace it with the given replacement, then return the updated map.
@@ -5367,6 +5465,43 @@ Map::from( ['a', 'b'] )->toJson( JSON_FORCE_OBJECT );
```
+### toReversed()
+
+Reverses the element order in a copy of the map (alias).
+
+```php
+public function toReversed() : self
+```
+
+* @return **self<int|string,mixed>** New map with a reversed copy of the elements
+
+This method is an alias for [reversed()](#reversed). For performance reasons, reversed() should be
+preferred because it uses one method call less than toReversed().
+
+**See also:**
+
+* [reversed()](#reversed) - Underlying method with same parameters and return value but better performance
+
+
+### toSorted()
+
+Sorts the elements in a copy of the map using new keys (alias).
+
+```php
+public function toSorted( int $options = SORT_REGULAR ) : self
+```
+
+* @param **int** `$options` Sort options for PHP `sort()`
+* @return **self<int|string,mixed>** New map with a sorted copy of the elements
+
+This method is an alias for [sorted()](#sorted). For performance reasons, sorted() should be
+preferred because it uses one method call less than toSorted().
+
+**See also:**
+
+* [sorted()](#sorted) - Underlying method with same parameters and return value but better performance
+
+
### toUrl()
Creates a HTTP query string from the map elements.
@@ -5388,6 +5523,49 @@ 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]
+```
+
+**See also:**
+
+* [map()](#map) - Maps new values to the existing keys using the passed function and returns a new map for the result
+* [rekey()](#rekey) - Changes the keys according to the passed function
+
+
### transpose()
Exchanges rows and columns for a two dimensional map.
diff --git a/composer.json b/composer.json
index ac52558..b5a66d5 100644
--- a/composer.json
+++ b/composer.json
@@ -11,7 +11,7 @@
"require-dev": {
"squizlabs/php_codesniffer": "^3.5",
"php-coveralls/php-coveralls": "~2.0",
- "phpunit/phpunit": "~7.0||~8.0||~9.0"
+ "phpunit/phpunit": "~7.0||~8.0||~9.0||~10.0||~11.0"
},
"autoload": {
"psr-4": {
diff --git a/src/Map.php b/src/Map.php
index 515d7cb..9c7ad55 100644
--- a/src/Map.php
+++ b/src/Map.php
@@ -317,7 +317,7 @@ public static function fromJson( string $json, int $options = JSON_BIGINT_AS_STR
* @param \Closure|null $fcn Anonymous function or NULL to return the closure if available
* @return \Closure|null Registered anonymous function or NULL if none has been registered
*/
- public static function method( string $method, \Closure $fcn = null ) : ?\Closure
+ public static function method( string $method, ?\Closure $fcn = null ) : ?\Closure
{
if( $fcn ) {
self::$methods[$method] = $fcn;
@@ -810,7 +810,7 @@ public function clone() : self
* @param string|null $indexcol Name or path of the index property
* @return self New map with mapped entries
*/
- public function col( string $valuecol = null, string $indexcol = null ) : self
+ public function col( ?string $valuecol = null, ?string $indexcol = null ) : self
{
$vparts = explode( $this->sep, (string) $valuecol );
$iparts = explode( $this->sep, (string) $indexcol );
@@ -864,7 +864,7 @@ public function col( string $valuecol = null, string $indexcol = null ) : self
* @return self New map with all sub-array elements added into it recursively, up to the specified depth
* @throws \InvalidArgumentException If depth must be greater or equal than 0 or NULL
*/
- public function collapse( int $depth = null ) : self
+ public function collapse( ?int $depth = null ) : self
{
if( $depth < 0 ) {
throw new \InvalidArgumentException( 'Depth must be greater or equal than 0 or NULL' );
@@ -984,7 +984,7 @@ public function concat( iterable $elements ) : self
* @param mixed $value Value used for comparison
* @return bool TRUE if at least one element is available in map, FALSE if the map contains none of them
*/
- public function contains( $key, string $operator = null, $value = null ) : bool
+ public function contains( $key, ?string $operator = null, $value = null ) : bool
{
if( $operator === null ) {
return $this->some( $key );
@@ -1046,7 +1046,7 @@ public function count() : int
* @param callable|null $callback Function with (value, key) parameters which returns the value to use for counting
* @return self New map with values as keys and their count as value
*/
- public function countBy( callable $callback = null ) : self
+ public function countBy( ?callable $callback = null ) : self
{
$callback = $callback ?: function( $value ) {
return (string) $value;
@@ -1075,7 +1075,7 @@ public function countBy( callable $callback = null ) : self
*
* @param callable|null $callback Function receiving the map elements as parameter (optional)
*/
- public function dd( callable $callback = null ) : void
+ public function dd( ?callable $callback = null ) : void
{
$this->dump( $callback );
exit( 1 );
@@ -1111,7 +1111,7 @@ public function dd( callable $callback = null ) : void
* @param callable|null $callback Function with (valueA, valueB) parameters and returns -1 (<), 0 (=) and 1 (>)
* @return self New map
*/
- public function diff( iterable $elements, callable $callback = null ) : self
+ public function diff( iterable $elements, ?callable $callback = null ) : self
{
if( $callback ) {
return new static( array_udiff( $this->list(), $this->array( $elements ), $callback ) );
@@ -1152,7 +1152,7 @@ public function diff( iterable $elements, callable $callback = null ) : self
* @param callable|null $callback Function with (valueA, valueB) parameters and returns -1 (<), 0 (=) and 1 (>)
* @return self New map
*/
- public function diffAssoc( iterable $elements, callable $callback = null ) : self
+ public function diffAssoc( iterable $elements, ?callable $callback = null ) : self
{
if( $callback ) {
return new static( array_diff_uassoc( $this->list(), $this->array( $elements ), $callback ) );
@@ -1192,7 +1192,7 @@ public function diffAssoc( iterable $elements, callable $callback = null ) : sel
* @param callable|null $callback Function with (keyA, keyB) parameters and returns -1 (<), 0 (=) and 1 (>)
* @return self New map
*/
- public function diffKeys( iterable $elements, callable $callback = null ) : self
+ public function diffKeys( iterable $elements, ?callable $callback = null ) : self
{
if( $callback ) {
return new static( array_diff_ukey( $this->list(), $this->array( $elements ), $callback ) );
@@ -1227,7 +1227,7 @@ public function diffKeys( iterable $elements, callable $callback = null ) : self
* @param callable|null $callback Function receiving the map elements as parameter (optional)
* @return self Same map for fluid interface
*/
- public function dump( callable $callback = null ) : self
+ public function dump( ?callable $callback = null ) : self
{
$callback ? $callback( $this->list() ) : print_r( $this->list() );
return $this;
@@ -1260,7 +1260,7 @@ public function dump( callable $callback = null ) : self
* @param string|null $key Key or path of the nested array or object to check for
* @return self New map
*/
- public function duplicates( string $key = null ) : self
+ public function duplicates( ?string $key = null ) : self
{
$list = $this->list();
$items = ( $key !== null ? $this->col( $key )->toArray() : $list );
@@ -1422,7 +1422,7 @@ public function except( $keys ) : self
* @param callable|null $callback Function with (item, key) parameters and returns TRUE/FALSE
* @return self New map
*/
- public function filter( callable $callback = null ) : self
+ public function filter( ?callable $callback = null ) : self
{
if( $callback ) {
return new static( array_filter( $this->list(), $callback, ARRAY_FILTER_USE_BOTH ) );
@@ -1563,7 +1563,7 @@ public function firstKey()
* @return self New map with all sub-array elements added into it recursively, up to the specified depth
* @throws \InvalidArgumentException If depth must be greater or equal than 0 or NULL
*/
- public function flat( int $depth = null ) : self
+ public function flat( ?int $depth = null ) : self
{
if( $depth < 0 ) {
throw new \InvalidArgumentException( 'Depth must be greater or equal than 0 or NULL' );
@@ -1899,7 +1899,7 @@ public function has( $key ) : bool
* @param \Closure|null $else Function with (map, condition) parameter (optional)
* @return self New map
*/
- public function if( $condition, \Closure $then = null, \Closure $else = null ) : self
+ public function if( $condition, ?\Closure $then = null, ?\Closure $else = null ) : self
{
if( $condition instanceof \Closure ) {
$condition = $condition( $this );
@@ -1952,7 +1952,7 @@ public function if( $condition, \Closure $then = null, \Closure $else = null ) :
* @param \Closure|null $else Function with (map, condition) parameter (optional)
* @return self New map
*/
- public function ifAny( \Closure $then = null, \Closure $else = null ) : self
+ public function ifAny( ?\Closure $then = null, ?\Closure $else = null ) : self
{
return $this->if( !empty( $this->list() ), $then, $else );
}
@@ -1990,7 +1990,7 @@ public function ifAny( \Closure $then = null, \Closure $else = null ) : self
* @param \Closure|null $else Function with (map, condition) parameter (optional)
* @return self New map
*/
- public function ifEmpty( \Closure $then = null, \Closure $else = null ) : self
+ public function ifEmpty( ?\Closure $then = null, ?\Closure $else = null ) : self
{
return $this->if( empty( $this->list() ), $then, $else );
}
@@ -2073,22 +2073,13 @@ public function in( $element, bool $strict = false ) : bool
/**
* Tests if the passed element or elements are part of the map.
*
- * Examples:
- * Map::from( ['a', 'b'] )->includes( 'a' );
- * Map::from( ['a', 'b'] )->includes( ['a', 'b'] );
- * Map::from( ['a', 'b'] )->includes( 'x' );
- * Map::from( ['a', 'b'] )->includes( ['a', 'x'] );
- * Map::from( ['1', '2'] )->includes( 2, true );
- *
- * Results:
- * The first and second example will return TRUE while the other ones will return FALSE
- *
* This method is an alias for in(). For performance reasons, in() should be
* preferred because it uses one method call less than includes().
*
* @param mixed|array $element Element or elements to search for in the map
* @param bool $strict TRUE to check the type too, using FALSE '1' and 1 will be the same
* @return bool TRUE if all elements are available in map, FALSE if not
+ * @see in() - Underlying method with same parameters and return value but better performance
*/
public function includes( $element, bool $strict = false ) : bool
{
@@ -2355,7 +2346,7 @@ public function int( $key, $default = 0 ) : int
* @param callable|null $callback Function with (valueA, valueB) parameters and returns -1 (<), 0 (=) and 1 (>)
* @return self New map
*/
- public function intersect( iterable $elements, callable $callback = null ) : self
+ public function intersect( iterable $elements, ?callable $callback = null ) : self
{
$list = $this->list();
$elements = $this->array( $elements );
@@ -2401,7 +2392,7 @@ public function intersect( iterable $elements, callable $callback = null ) : sel
* @param callable|null $callback Function with (valueA, valueB) parameters and returns -1 (<), 0 (=) and 1 (>)
* @return self New map
*/
- public function intersectAssoc( iterable $elements, callable $callback = null ) : self
+ public function intersectAssoc( iterable $elements, ?callable $callback = null ) : self
{
$elements = $this->array( $elements );
@@ -2444,7 +2435,7 @@ public function intersectAssoc( iterable $elements, callable $callback = null )
* @param callable|null $callback Function with (keyA, keyB) parameters and returns -1 (<), 0 (=) and 1 (>)
* @return self New map
*/
- public function intersectKeys( iterable $elements, callable $callback = null ) : self
+ public function intersectKeys( iterable $elements, ?callable $callback = null ) : self
{
$list = $this->list();
$elements = $this->array( $elements );
@@ -2850,7 +2841,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 ) {
@@ -2864,6 +2855,8 @@ public function ltrim( string $chars = " \n\r\t\v\x00" ) : self
*
* @param callable $callback Function with (value, key) parameters and returns computed result
* @return self New map with the original keys and the computed values
+ * @see rekey() - Changes the keys according to the passed function
+ * @see transform() - Creates new key/value pairs using the passed function and returns a new map for the result
*/
public function map( callable $callback ) : self
{
@@ -3354,8 +3347,9 @@ public function pipe( \Closure $callback )
* @param string|null $valuecol Name or path of the value property
* @param string|null $indexcol Name or path of the index property
* @return self New map with mapped entries
+ * @see col() - Underlying method with same parameters and return value but better performance
*/
- public function pluck( string $valuecol = null, string $indexcol = null ) : self
+ public function pluck( ?string $valuecol = null, ?string $indexcol = null ) : self
{
return $this->col( $valuecol, $indexcol );
}
@@ -3449,7 +3443,7 @@ public function pos( $value ) : ?int
* @param int|null $depth Maximum depth to dive into multi-dimensional arrays starting from "1"
* @return self Updated map for fluid interface
*/
- public function prefix( $prefix, int $depth = null ) : self
+ public function prefix( $prefix, ?int $depth = null ) : self
{
$fcn = function( array $list, $prefix, int $depth ) use ( &$fcn ) {
@@ -3478,6 +3472,7 @@ public function prefix( $prefix, int $depth = null ) : self
* @param mixed $value Item to add at the beginning
* @param int|string|null $key Key for the item or NULL to reindex all numerical keys
* @return self Updated map for fluid interface
+ * @see unshift() - Underlying method with same parameters and return value but better performance
*/
public function prepend( $value, $key = null ) : self
{
@@ -3536,19 +3531,13 @@ public function push( $value ) : self
/**
* Sets the given key and value in the map without returning a new map.
*
- * Examples:
- * Map::from( ['a'] )->put( 1, 'b' );
- * Map::from( ['a'] )->put( 0, 'b' );
- *
- * Results:
- * The first example results in ['a', 'b'] while the second one produces ['b']
- *
* This method is an alias for set(). For performance reasons, set() should be
* preferred because it uses one method call less than put().
*
* @param int|string $key Key to set the new value for
* @param mixed $value New element that should be set
* @return self Updated map for fluid interface
+ * @see set() - Underlying method with same parameters and return value but better performance
*/
public function put( $key, $value ) : self
{
@@ -3668,6 +3657,8 @@ public function reject( $callback = true ) : self
*
* @param callable $callback Function with (value, key) parameters and returns new key
* @return self New map with new keys and original values
+ * @see map() - Maps new values to the existing keys using the passed function and returns a new map for the result
+ * @see transform() - Creates new key/value pairs using the passed function and returns a new map for the result
*/
public function rekey( callable $callback ) : self
{
@@ -3749,6 +3740,7 @@ public function replace( iterable $elements, bool $recursive = true ) : self
* The keys are preserved using this method.
*
* @return self Updated map for fluid interface
+ * @see reversed() - Reverses the element order in a copy of the map
*/
public function reverse() : self
{
@@ -3757,6 +3749,29 @@ public function reverse() : self
}
+ /**
+ * Reverses the element order in a copy of the map.
+ *
+ * Examples:
+ * Map::from( ['a', 'b'] )->reversed();
+ * Map::from( ['name' => 'test', 'last' => 'user'] )->reversed();
+ *
+ * Results:
+ * ['b', 'a']
+ * ['last' => 'user', 'name' => 'test']
+ *
+ * The keys are preserved using this method and a new map is created before reversing the elements.
+ * Thus, reverse() should be preferred for performance reasons if possible.
+ *
+ * @return self New map with a reversed copy of the elements
+ * @see reverse() - Reverses the element order with keys without returning a new map
+ */
+ public function reversed() : self
+ {
+ return ( clone $this )->reverse();
+ }
+
+
/**
* Sorts all elements in reverse order using new keys.
*
@@ -3927,6 +3942,7 @@ public function shift()
*
* @param bool $assoc True to preserve keys, false to assign new keys
* @return self Updated map for fluid interface
+ * @see shuffled() - Shuffles the elements in a copy of the map
*/
public function shuffle( bool $assoc = false ) : self
{
@@ -3948,11 +3964,32 @@ public function shuffle( bool $assoc = false ) : self
shuffle( $this->list() );
}
-
return $this;
}
+ /**
+ * Shuffles the elements in a copy of the map.
+ *
+ * Examples:
+ * Map::from( [2 => 'a', 4 => 'b'] )->shuffled();
+ * Map::from( [2 => 'a', 4 => 'b'] )->shuffled( true );
+ *
+ * Results:
+ * The map in the first example will contain "a" and "b" in random order and
+ * with new keys assigned. The second call will also return all values in
+ * random order but preserves the keys of the original list.
+ *
+ * @param bool $assoc True to preserve keys, false to assign new keys
+ * @return self New map with a shuffled copy of the elements
+ * @see shuffle() - Shuffles the elements in the map without returning a new map
+ */
+ public function shuffled( bool $assoc = false ) : self
+ {
+ return ( clone $this )->shuffle( $assoc );
+ }
+
+
/**
* Returns a new map with the given number of items skipped.
*
@@ -4027,7 +4064,7 @@ public function skip( $offset ) : self
* @param int|null $length Number of elements to return or NULL for no limit
* @return self New map
*/
- public function slice( int $offset, int $length = null ) : self
+ public function slice( int $offset, ?int $length = null ) : self
{
return new static( array_slice( $this->list(), $offset, $length, true ) );
}
@@ -4086,7 +4123,7 @@ public function some( $values, bool $strict = false ) : bool
/**
- * Sorts all elements using new keys.
+ * Sorts all elements in-place using new keys.
*
* Examples:
* Map::from( ['a' => 1, 'b' => 0] )->sort();
@@ -4106,8 +4143,9 @@ public function some( $values, bool $strict = false ) : bool
*
* The keys aren't preserved and elements get a new index. No new map is created.
*
- * @param int $options Sort options for sort()
+ * @param int $options Sort options for PHP sort()
* @return self Updated map for fluid interface
+ * @see sorted() - Sorts elements in a copy of the map
*/
public function sort( int $options = SORT_REGULAR ) : self
{
@@ -4116,6 +4154,38 @@ public function sort( int $options = SORT_REGULAR ) : self
}
+ /**
+ * Sorts the elements in a copy of the map using new keys.
+ *
+ * Examples:
+ * Map::from( ['a' => 1, 'b' => 0] )->sorted();
+ * Map::from( [0 => 'b', 1 => 'a'] )->sorted();
+ *
+ * Results:
+ * [0 => 0, 1 => 1]
+ * [0 => 'a', 1 => 'b']
+ *
+ * The parameter modifies how the values are compared. Possible parameter values are:
+ * - SORT_REGULAR : compare elements normally (don't change types)
+ * - SORT_NUMERIC : compare elements numerically
+ * - SORT_STRING : compare elements as strings
+ * - SORT_LOCALE_STRING : compare elements as strings, based on the current locale or changed by setlocale()
+ * - SORT_NATURAL : compare elements as strings using "natural ordering" like natsort()
+ * - SORT_FLAG_CASE : use SORT_STRING|SORT_FLAG_CASE and SORT_NATURALSORT_FLAG_CASE to sort strings case-insensitively
+ *
+ * The keys aren't preserved and elements get a new index and a new map is created before sorting the elements.
+ * Thus, sort() should be preferred for performance reasons if possible.
+ *
+ * @param int $options Sort options for PHP sort()
+ * @return self New map with a sorted copy of the elements
+ * @see sort() - Sorts elements in-place in the original map
+ */
+ public function sorted( int $options = SORT_REGULAR ) : self
+ {
+ return ( clone $this )->sort( $options );
+ }
+
+
/**
* Removes a portion of the map and replace it with the given replacement, then return the updated map.
*
@@ -4146,7 +4216,7 @@ public function sort( int $options = SORT_REGULAR ) : self
* @param mixed $replacement List of elements to insert
* @return self New map
*/
- public function splice( int $offset, int $length = null, $replacement = [] ) : self
+ public function splice( int $offset, ?int $length = null, $replacement = [] ) : self
{
if( $length === null ) {
$length = count( $this->list() );
@@ -4716,7 +4786,7 @@ public function strUpper( string $encoding = 'UTF-8' ) :self
* @param int|null $depth Maximum depth to dive into multi-dimensional arrays starting from "1"
* @return self Updated map for fluid interface
*/
- public function suffix( $suffix, int $depth = null ) : self
+ public function suffix( $suffix, ?int $depth = null ) : self
{
$fcn = function( $list, $suffix, $depth ) use ( &$fcn ) {
@@ -4890,6 +4960,37 @@ public function toJson( int $options = 0 ) : ?string
}
+ /**
+ * Reverses the element order in a copy of the map (alias).
+ *
+ * This method is an alias for reversed(). For performance reasons, reversed() should be
+ * preferred because it uses one method call less than toReversed().
+ *
+ * @return self New map with a reversed copy of the elements
+ * @see reversed() - Underlying method with same parameters and return value but better performance
+ */
+ public function toReversed() : self
+ {
+ return $this->reversed();
+ }
+
+
+ /**
+ * Sorts the elements in a copy of the map using new keys (alias).
+ *
+ * This method is an alias for sorted(). For performance reasons, sorted() should be
+ * preferred because it uses one method call less than toSorted().
+ *
+ * @param int $options Sort options for PHP sort()
+ * @return self New map with a sorted copy of the elements
+ * @see sorted() - Underlying method with same parameters and return value but better performance
+ */
+ public function toSorted( int $options = SORT_REGULAR ) : self
+ {
+ return $this->sorted( $options );
+ }
+
+
/**
* Creates a HTTP query string from the map elements.
*
@@ -4909,6 +5010,51 @@ 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
+ * @see map() - Maps new values to the existing keys using the passed function and returns a new map for the result
+ * @see rekey() - Changes the keys according to the passed function
+ */
+ 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.
*
@@ -5018,7 +5164,7 @@ public function transpose() : self
* @param string $nestKey Key to the children of each item
* @return self New map with all items as flat list
*/
- public function traverse( \Closure $callback = null, string $nestKey = 'children' ) : self
+ public function traverse( ?\Closure $callback = null, string $nestKey = 'children' ) : self
{
$result = [];
$this->visit( $this->list(), $result, 0, $callback, $nestKey );
@@ -5233,7 +5379,7 @@ public function union( iterable $elements ) : self
* @param string|null $key Key or path of the nested array or object to check for
* @return self New map
*/
- public function unique( string $key = null ) : self
+ public function unique( ?string $key = null ) : self
{
if( $key !== null ) {
return $this->col( null, $key )->values();
diff --git a/tests/MapTest.php b/tests/MapTest.php
index a19fc66..1bc6fc6 100644
--- a/tests/MapTest.php
+++ b/tests/MapTest.php
@@ -1247,20 +1247,14 @@ public function testGrepException()
{
set_error_handler( function( $errno, $str, $file, $line ) { return true; } );
- $this->expectException( \RuntimeException::class );
- Map::from( [] )->grep( 'b' );
- }
-
-
- public function testGrepWarning()
- {
- if( method_exists( $this, 'expectWarning' ) ) {
- $this->expectWarning(); // PHPUnit 8+
- } else {
- $this->expectException( \PHPUnit\Framework\Error\Warning::class ); // PHP 7.1
+ try {
+ Map::from( [] )->grep( 'b' );
+ $this->fail( 'An expected RuntimeException has not been raised' );
+ } catch( \RuntimeException $e ) {
+ $this->assertStringContainsString( 'Regular expression error', $e->getMessage() );
+ } finally {
+ restore_error_handler();
}
-
- Map::from( [] )->grep( 'b' );
}
@@ -2606,6 +2600,17 @@ public function testReverseKeys()
}
+ public function testReversed()
+ {
+ $m = new Map( ['hello', 'world'] );
+ $r = $m->reversed();
+
+ $this->assertNotSame( $r, $m );
+ $this->assertInstanceOf( Map::class, $r );
+ $this->assertSame( [1 => 'world', 0 => 'hello'], $r->toArray() );
+ }
+
+
public function testRsortNummeric()
{
$m = ( new Map( [-1, -3, -2, -4, -5, 0, 5, 3, 1, 2, 4] ) )->rsort();
@@ -2719,6 +2724,17 @@ public function testShuffleAssoc()
}
+ public function testShuffled()
+ {
+ $m = new Map( range( 0, 100, 10 ) );
+ $r = $m->shuffled();
+
+ $this->assertNotSame( $r, $m );
+ $this->assertInstanceOf( Map::class, $r );
+ $this->assertNotEquals( $r->toArray(), $m->toArray() );
+ }
+
+
public function testSkip()
{
$this->assertSame( [2 => 3, 3 => 4], Map::from( [1, 2, 3, 4] )->skip( 2 )->toArray() );
@@ -2835,6 +2851,17 @@ public function testSomeCallback()
}
+ public function testSorted()
+ {
+ $m = new Map( [-1, -3, -2, -4, -5, 0, 5, 3, 1, 2, 4] );
+ $n = $m->sorted();
+
+ $this->assertNotSame( $n, $m );
+ $this->assertInstanceOf( Map::class, $n );
+ $this->assertSame( [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5], $n->toArray() );
+ }
+
+
public function testSortNummeric()
{
$m = ( new Map( [-1, -3, -2, -4, -5, 0, 5, 3, 1, 2, 4] ) )->sort();
@@ -3204,6 +3231,72 @@ public function testTimesObjects()
}
+ public function testToReversed()
+ {
+ $m = new Map( ['hello', 'world'] );
+ $r = $m->toReversed();
+
+ $this->assertNotSame( $r, $m );
+ $this->assertInstanceOf( Map::class, $r );
+ $this->assertSame( [1 => 'world', 0 => 'hello'], $r->toArray() );
+ }
+
+
+ public function testToSorted()
+ {
+ $m = new Map( [-1, -3, -2, -4, -5, 0, 5, 3, 1, 2, 4] );
+ $n = $m->toSorted();
+
+ $this->assertNotSame( $n, $m );
+ $this->assertInstanceOf( Map::class, $n );
+ $this->assertSame( [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5], $n->toArray() );
+ }
+
+
+ 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( [