Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/mpetrovich/dash
Browse files Browse the repository at this point in the history
  • Loading branch information
mpetrovich committed Feb 23, 2020
2 parents e0beaa0 + ed60d8f commit 60b88a7
Show file tree
Hide file tree
Showing 5 changed files with 300 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ echo "Average male age is $avgMaleAge.";
[findLastValue](docs/Operations.md#findlastvalue),
[findValue](docs/Operations.md#findvalue),
[first / head](docs/Operations.md#first--head),
[flatten](docs/Operations.md#flatten),
[get](docs/Operations.md#get),
[getDirect](docs/Operations.md#getdirect),
[getDirectRef](docs/Operations.md#getdirectref),
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"src/findLastValue.php",
"src/findValue.php",
"src/first.php",
"src/flatten.php",
"src/get.php",
"src/getDirect.php",
"src/getDirectRef.php",
Expand Down
46 changes: 46 additions & 0 deletions docs/Operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Operation | Signature | Curried
[findLastValue](#findlastvalue) | `findLastValue($iterable, $predicate = 'Dash\identity'): mixed\|null` | `Curry\findLastValue`
[findValue](#findvalue) | `findValue($iterable, $predicate = 'Dash\identity'): mixed\|null` | `Curry\findValue`
[first](#first--head) / head | `first($iterable): mixed\|null` | `Curry\first`
[flatten](#flatten) | `flatten($iterable): array` |
[get](#get) | `get($input, $path, $default = null): mixed` | `Curry\get`
[getDirect](#getdirect) | `getDirect($input, $key, $default = null): mixed` | `Curry\getDirect`
[getDirectRef](#getdirectref) | `getDirectRef(&$input, $key): mixed` |
Expand Down Expand Up @@ -1454,6 +1455,51 @@ Dash\first([]);

[↑ Top](#operations)

flatten
---
See also: `groupBy()`

```php
flatten($iterable): array
```
Gets a list of nested elements in `$iterable`.

Keys in `$iterable` are not preserved.


Parameter | Type | Description
--- | --- | :---
`$iterable` | `iterable\|stdClass\|null` |
**Returns** | `array` | List of elements in `$iterable`, including elements of directly nested iterables.

**Example:**
```php
Dash\flatten([[1, 2], [3, 4]]);
// === [1, 2, 3, 4]

Dash\flatten([['a' => 1, 'b' => 2], ['c' => 3]]);
// === [1, 2, 3]

```

**Example:** With a mix of nested and non-nested iterables
```php
Dash\flatten([1, 2, [3, 4]]);
// === [1, 2, 3, 4]

```

**Example:** Deeply nested array
```php
Dash\flatten([
[1, 2],
[[3, 4]]
]);
// === [1, 2, [3, 4]]
```

[↑ Top](#operations)

get
---
See also: `getDirect()`, `has()`, `property()`
Expand Down
40 changes: 40 additions & 0 deletions src/flatten.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace Dash;

/**
* Gets a list of nested elements in `$iterable`.
*
* Keys in `$iterable` are not preserved.
*
* @see groupBy()
*
* @param iterable|stdClass|null $iterable
* @return array List of elements in `$iterable`, including elements of directly nested iterables.
*
* @example
Dash\flatten([[1, 2], [3, 4]]);
// === [1, 2, 3, 4]
Dash\flatten([['a' => 1, 'b' => 2], ['c' => 3]]);
// === [1, 2, 3]
*
* @example With a mix of nested and non-nested iterables
Dash\flatten([1, 2, [3, 4]]);
// === [1, 2, 3, 4]
*
* @example Deeply nested array
Dash\flatten([
[1, 2],
[[3, 4]]
]);
// === [1, 2, [3, 4]]
*/
function flatten($iterable)
{
assertType($iterable, ['iterable', 'stdClass', 'null'], __FUNCTION__);

return reduce($iterable, function ($flattened, $value) {
return array_merge($flattened, is_array($value) ? array_values($value) : [$value]);
}, []);
}
212 changes: 212 additions & 0 deletions tests/flattenTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
<?php

/**
* @covers Dash\flatten
*/
class flattenTest extends PHPUnit_Framework_TestCase
{
/**
* @dataProvider cases
*/
public function test($iterable, $expected)
{
$this->assertSame($expected, Dash\flatten($iterable));
}

public function cases()
{
$stdClass = (object) ['c' => 10, 'd' => 11];
$arrayObject = new ArrayObject(['e' => 12, 'f' => 13]);

return [
'With nulls' => [
'iterable' => [null, null, null],
'expected' => [null, null, null],
],
'With empty iterable' => [
'iterable' => [],
'expected' => [],
],

/*
With indexed array
*/

'With an indexed array with only scalar values' => [
'iterable' => [
6,
1,
3,
],
'expected' => [6, 1, 3]
],
'With an indexed array with a mix of scalar and non-scalar values' => [
'iterable' => [
4,
[2, 3],
['a' => 7, 'b' => 9],
$stdClass,
$arrayObject,
8,
],
'expected' => [4, 2, 3, 7, 9, $stdClass, $arrayObject, 8]
],
'With an indexed array with only array values' => [
'iterable' => [
[2, 3],
[7,9],
],
'expected' => [2, 3, 7, 9]
],

/*
With associative array
*/

'With an associative array with only scalar values' => [
'iterable' => [
'a' => 6,
'b' => 1,
'c' => 3,
],
'expected' => [ 6, 1, 3]
],
'With an associative array with a mix of scalar and non-scalar values' => [
'iterable' => [
'a' => 4,
'b' => [2, 3],
'c' => ['a' => 7, 'b' => 9],
'd' => $stdClass,
'e' => $arrayObject,
'f' => 8,
],
'expected' => [4, 2, 3, 7, 9, $stdClass, $arrayObject, 8]
],
'With an associative array with only array values' => [
'iterable' => [
'b' => [2, 3],
'c' => [7,9],
],
'expected' => [2, 3, 7, 9]
],

/*
With stdClass
*/

'With an stdClass with only scalar values' => [
'iterable' => (object) [
'a' => 6,
'b' => 1,
'c' => 3,
],
'expected' => [6, 1, 3]
],
'With an stdClass with a mix of scalar and non-scalar values' => [
'iterable' => (object) [
'a' => 4,
'b' => [2, 3],
'c' => ['a' => 7, 'b' => 9],
'd' => $stdClass,
'e' => $arrayObject,
'f' => 8,
],
'expected' => [4, 2, 3, 7, 9, $stdClass, $arrayObject, 8]
],
'With an stdClass with only array values' => [
'iterable' => (object) [
'b' => [2, 3],
'c' => [7,9],
],
'expected' => [2, 3, 7, 9]
],

/*
With ArrayObject
*/

'With an ArrayObject with only scalar values' => [
'iterable' => new ArrayObject([
'a' => 6,
'b' => 1,
'c' => 3,
]),
'expected' => [6, 1, 3]
],
'With an ArrayObject with a mix of scalar and non-scalar values' => [
'iterable' => new ArrayObject([
'a' => 4,
'b' => [2, 3],
'c' => ['a' => 7, 'b' => 9],
'd' => $stdClass,
'e' => $arrayObject,
'f' => 8,
]),
'expected' => [4, 2, 3, 7, 9, $stdClass, $arrayObject, 8]
],
'With an ArrayObject with only array values' => [
'iterable' => new ArrayObject([
'b' => [2, 3],
'c' => [7,9],
]),
'expected' => [2, 3, 7, 9]
],

/*
Edge cases
*/

'With deeply nested arrays' => [
'iterable' => [
[1, 2],
[[3, 4]]
],
'expected' => [1, 2, [3, 4]]
]
];
}

/**
* @dataProvider casesTypeAssertions
* @expectedException InvalidArgumentException
*/
public function testTypeAssertions($iterable, $type)
{
try {
Dash\flatten($iterable);
}
catch (Exception $e) {
$this->assertSame(
"Dash\\flatten expects iterable or stdClass or null but was given $type",
$e->getMessage()
);
throw $e;
}
}

public function casesTypeAssertions()
{
return [
'With an empty string' => [
'iterable' => '',
'type' => 'string',
],
'With a string' => [
'iterable' => 'hello',
'type' => 'string',
],
'With a zero number' => [
'iterable' => 0,
'type' => 'integer',
],
'With a number' => [
'iterable' => 3.14,
'type' => 'double',
],
'With a DateTime' => [
'iterable' => new DateTime(),
'type' => 'DateTime',
],
];
}
}

0 comments on commit 60b88a7

Please sign in to comment.