Skip to content

Commit 9285aa6

Browse files
committed
Implemented flatten() method
1 parent d84f8e6 commit 9285aa6

File tree

3 files changed

+132
-23
lines changed

3 files changed

+132
-23
lines changed

README.md

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ will return:
165165
<a href="#first">first</a>
166166
<a href="#firstkey">firstKey</a>
167167
<a href="#flat">flat</a>
168+
<a href="#flatten">flatten</a>
168169
<a href="#flip">flip</a>
169170
<a href="#float">float</a>
170171
<a href="#from">from</a>
@@ -473,6 +474,7 @@ will return:
473474
* [collapse()](#collapse) : Collapses multi-dimensional elements overwriting elements
474475
* [combine()](#combine) : Combines the map elements as keys with the given values
475476
* [flat()](#flat) : Flattens multi-dimensional elements without overwriting elements
477+
* [flatten()](#flatten) : Creates a new map with keys joined recursively
476478
* [flip()](#flip) : Exchanges keys with their values
477479
* [groupBy()](#groupby) : Groups associative array elements or objects
478480
* [join()](#join) : Returns concatenated elements as string with separator
@@ -2364,6 +2366,39 @@ Map::from( [[0, 1], Map::from( [[2, 3], 4] )] )->flat();
23642366
* [collapse()](#collapse) - Collapses all sub-array elements recursively to a new map
23652367

23662368

2369+
### flatten()
2370+
2371+
c.
2372+
2373+
```php
2374+
public function flatten( ?int $depth = null ) : self
2375+
```
2376+
2377+
* @param **int&#124;null** `$depth` Number of levels to flatten multi-dimensional arrays or NULL for all
2378+
* @return **self&#60;string,mixed&#62;** New map with keys joined recursively, up to the specified depth
2379+
2380+
To create the original multi-dimensional array again, use the [unflatten()](#unflatten) method.
2381+
2382+
**Examples:**
2383+
2384+
```php
2385+
Map::from( ['a' => ['b' => ['c' => 1, 'd' => 2]], 'b' => ['e' => 3]] )->flatten();
2386+
// ['a/b/c' => 1, 'a/b/d' => 2, 'b/e' => 3]
2387+
2388+
Map::from( ['a' => ['b' => ['c' => 1, 'd' => 2]], 'b' => ['e' => 3]] )->flatten( 1 );
2389+
// ['a/b' => ['c' => 1, 'd' => 2], 'b/e' => 3]
2390+
2391+
Map::from( ['a' => ['b' => ['c' => 1, 'd' => 2]], 'b' => ['e' => 3]] )->sep( '.' )->flatten();
2392+
// ['a.b.c' => 1, 'a.b.d' => 2, 'b.e' => 3]
2393+
```
2394+
2395+
**See also:**
2396+
2397+
* [flat()](#flat) - Flattens multi-dimensional elements without overwriting elements
2398+
* [collapse()](#collapse) - Collapses all sub-array elements recursively to a new map
2399+
* [unflatten()](#unflatten) - Unflattens the key path/value pairs into a multi-dimensional array
2400+
2401+
23672402
### flip()
23682403

23692404
Exchanges the keys with their values and vice versa.
@@ -6975,6 +7010,8 @@ Unflattens the key path/value pairs into a multi-dimensional array.
69757010
public function unflatten() : self
69767011
```
69777012

7013+
This is the inverse method for [flatten()](#flatten).
7014+
69787015
* @return **self&#60;string,mixed&#62;** New map with multi-dimensional arrays
69797016

69807017
**Examples:**
@@ -6989,8 +7026,9 @@ Map::from( ['a.b.c' => 1, 'a.b.d' => 2, 'b.e' => 3] )->sep( '.' )->unflatten();
69897026

69907027
**See also:**
69917028

6992-
* [flat()](#flat) - Flattens multi-dimensional elements without overwriting elements
69937029
* [collapse()](#collapse) - Collapses all sub-array elements recursively to a new map
7030+
* [flat()](#flat) - Flattens multi-dimensional elements without overwriting elements
7031+
* [flatten()](#flatten) - Creates a new map with keys joined recursively
69947032

69957033

69967034
### union()

src/Map.php

Lines changed: 76 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1767,7 +1767,7 @@ public function firstKey( $default = null )
17671767

17681768

17691769
/**
1770-
* Creates a new map with all sub-array elements added recursively withput overwriting existing keys.
1770+
* Creates a new map with all sub-array elements added recursively without overwriting existing keys.
17711771
*
17721772
* Examples:
17731773
* Map::from( [[0, 1], [2, 3]] )->flat();
@@ -1800,7 +1800,38 @@ public function flat( ?int $depth = null ) : self
18001800
}
18011801

18021802
$result = [];
1803-
$this->flatten( $this->list(), $result, $depth ?? 0x7fffffff );
1803+
$this->nflatten( $this->list(), $result, $depth ?? 0x7fffffff );
1804+
return new static( $result );
1805+
}
1806+
1807+
1808+
/**
1809+
* Creates a new map with keys joined recursively.
1810+
*
1811+
* Examples:
1812+
* Map::from( ['a' => ['b' => ['c' => 1, 'd' => 2]], 'b' => ['e' => 3]] )->flatten();
1813+
* Map::from( ['a' => ['b' => ['c' => 1, 'd' => 2]], 'b' => ['e' => 3]] )->flatten( 1 );
1814+
* Map::from( ['a' => ['b' => ['c' => 1, 'd' => 2]], 'b' => ['e' => 3]] )->sep( '.' )->flatten();
1815+
*
1816+
* Results:
1817+
* ['a/b/c' => 1, 'a/b/d' => 2, 'b/e' => 3]
1818+
* ['a/b' => ['c' => 1, 'd' => 2], 'b/e' => 3]
1819+
* ['a.b.c' => 1, 'a.b.d' => 2, 'b.e' => 3]
1820+
*
1821+
* To create the original multi-dimensional array again, use the unflatten() method.
1822+
*
1823+
* @param int|null $depth Number of levels to flatten multi-dimensional arrays or NULL for all
1824+
* @return self<string,mixed> New map with keys joined recursively, up to the specified depth
1825+
* @throws \InvalidArgumentException If depth must be greater or equal than 0 or NULL
1826+
*/
1827+
public function flatten( ?int $depth = null ) : self
1828+
{
1829+
if( $depth < 0 ) {
1830+
throw new \InvalidArgumentException( 'Depth must be greater or equal than 0 or NULL' );
1831+
}
1832+
1833+
$result = [];
1834+
$this->rflatten( $this->list(), $result, $depth ?? 0x7fffffff );
18041835
return new static( $result );
18051836
}
18061837

@@ -5810,6 +5841,8 @@ public function uksorted( callable $callback ) : self
58105841
* Results:
58115842
* ['a' => ['b' => ['c' => 1, 'd' => 2]], 'b' => ['e' => 3]]
58125843
*
5844+
* This is the inverse method for flatten().
5845+
*
58135846
* @return self<int|string,mixed> New map with multi-dimensional arrays
58145847
*/
58155848
public function unflatten() : self
@@ -6225,26 +6258,6 @@ protected function array( $elements ) : array
62256258
}
62266259

62276260

6228-
/**
6229-
* Flattens a multi-dimensional array or map into a single level array.
6230-
*
6231-
* @param iterable<int|string,mixed> $entries Single of multi-level array, map or everything foreach can be used with
6232-
* @param array<mixed> &$result Will contain all elements from the multi-dimensional arrays afterwards
6233-
* @param int $depth Number of levels to flatten in multi-dimensional arrays
6234-
*/
6235-
protected function flatten( iterable $entries, array &$result, int $depth ) : void
6236-
{
6237-
foreach( $entries as $entry )
6238-
{
6239-
if( is_iterable( $entry ) && $depth > 0 ) {
6240-
$this->flatten( $entry, $result, $depth - 1 );
6241-
} else {
6242-
$result[] = $entry;
6243-
}
6244-
}
6245-
}
6246-
6247-
62486261
/**
62496262
* Flattens a multi-dimensional array or map into a single level array.
62506263
*
@@ -6300,6 +6313,47 @@ protected function mapper( $key = null ) : \Closure
63006313
}
63016314

63026315

6316+
/**
6317+
* Flattens a multi-dimensional array or map into a single level array.
6318+
*
6319+
* @param iterable<int|string,mixed> $entries Single of multi-level array, map or everything foreach can be used with
6320+
* @param array<mixed> &$result Will contain all elements from the multi-dimensional arrays afterwards
6321+
* @param int $depth Number of levels to flatten in multi-dimensional arrays
6322+
*/
6323+
protected function nflatten( iterable $entries, array &$result, int $depth ) : void
6324+
{
6325+
foreach( $entries as $entry )
6326+
{
6327+
if( is_iterable( $entry ) && $depth > 0 ) {
6328+
$this->nflatten( $entry, $result, $depth - 1 );
6329+
} else {
6330+
$result[] = $entry;
6331+
}
6332+
}
6333+
}
6334+
6335+
6336+
/**
6337+
* Flattens a multi-dimensional array or map into an array with joined keys.
6338+
*
6339+
* @param iterable<int|string,mixed> $entries Single of multi-level array, map or everything foreach can be used with
6340+
* @param array<int|string,mixed> $result Will contain joined key/value pairs from the multi-dimensional arrays afterwards
6341+
* @param int $depth Number of levels to flatten in multi-dimensional arrays
6342+
* @param string $path Path prefix of the current key
6343+
*/
6344+
protected function rflatten( iterable $entries, array &$result, int $depth, string $path = '' ) : void
6345+
{
6346+
foreach( $entries as $key => $entry )
6347+
{
6348+
if( is_iterable( $entry ) && $depth > 0 ) {
6349+
$this->rflatten( $entry, $result, $depth - 1, $path . $key . $this->sep );
6350+
} else {
6351+
$result[$path . $key] = $entry;
6352+
}
6353+
}
6354+
}
6355+
6356+
63036357
/**
63046358
* Returns the position of the first element that doesn't match the condition
63056359
*

tests/MapTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,6 +1211,23 @@ public function testFlatException()
12111211
}
12121212

12131213

1214+
public function testFlatten()
1215+
{
1216+
$a = ['a' => ['b' => ['c' => 1, 'd' => 2]], 'b' => ['e' => 3]];
1217+
1218+
$this->assertSame( ['a/b/c' => 1, 'a/b/d' => 2, 'b/e' => 3], Map::from( $a )->flatten()->toArray() );
1219+
$this->assertSame( ['a/b' => ['c' => 1, 'd' => 2], 'b/e' => 3], Map::from( $a )->flatten( 1 )->toArray() );
1220+
$this->assertSame( ['a.b.c' => 1, 'a.b.d' => 2, 'b.e' => 3], Map::from( $a )->sep( '.' )->flatten()->toArray() );
1221+
}
1222+
1223+
1224+
public function testFlattenException()
1225+
{
1226+
$this->expectException( \InvalidArgumentException::class );
1227+
Map::from( [] )->flatten( -1 );
1228+
}
1229+
1230+
12141231
public function testFlip()
12151232
{
12161233
$m = Map::from( ['a' => 'X', 'b' => 'Y'] );

0 commit comments

Comments
 (0)