Skip to content

Commit f705886

Browse files
authored
Merge pull request #7 from chadicus/fea/unique
Add Arrays::unique()
2 parents da4b4ab + 45f124e commit f705886

File tree

5 files changed

+146
-0
lines changed

5 files changed

+146
-0
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ $value = \TraderInteractive\Filter\Arrays::pad([1, 2], 5, 0, \TraderInteractive\
8484
assert($value === [0, 0, 0, 1, 2]);
8585
```
8686

87+
#### Arrays::unique
88+
89+
This filter removes any duplicate values in the given array. Optionally throwing an exception if duplicate values are found.
90+
91+
```php
92+
$value = \TraderInteractive\Filter\Arrays::unique(['foo', 'bar', 'foo']);
93+
assert($value === ['foo', 'bar']);
94+
```
95+
8796
## Project Build
8897

8998
With a checkout of the code get [Composer](http://getcomposer.org) in your PATH and run:

src/Arrays.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use InvalidArgumentException;
66
use TraderInteractive\Exceptions\FilterException;
7+
use TraderInteractive\Filter\Exceptions\DuplicateValuesException;
78

89
/**
910
* A collection of filters for arrays.
@@ -20,6 +21,26 @@ final class Arrays
2021
*/
2122
const ARRAY_PAD_FRONT = 2;
2223

24+
/**
25+
* @var int
26+
*/
27+
const ARRAY_UNIQUE_SORT_REGULAR = \SORT_REGULAR;
28+
29+
/**
30+
* @var int
31+
*/
32+
const ARRAY_UNIQUE_SORT_NUMERIC = \SORT_NUMERIC;
33+
34+
/**
35+
* @var int
36+
*/
37+
const ARRAY_UNIQUE_SORT_STRING = \SORT_STRING;
38+
39+
/**
40+
* @var int
41+
*/
42+
const ARRAY_UNIQUE_SORT_LOCALE_STRING = \SORT_LOCALE_STRING;
43+
2344
/**
2445
* Filter an array by throwing if not an array or count not in the min/max range.
2546
*
@@ -189,4 +210,45 @@ public static function pad(array $input, int $size, $padValue = null, int $padTy
189210

190211
return $input;
191212
}
213+
214+
/**
215+
* Removes duplicate values from an array.
216+
*
217+
* @param array $input The array to be filtered.
218+
* @param int $sortFlags Optional parameter used to modify the sorting behavior.
219+
* @param bool $strict If set to TRUE the filter will throw exception if the $input array contains duplicates.
220+
*
221+
* @return array
222+
*
223+
* @throws FilterException Thrown if the array contains duplicates and $strict is true.
224+
*/
225+
public static function unique(
226+
array $input,
227+
int $sortFlags = self::ARRAY_UNIQUE_SORT_REGULAR,
228+
bool $strict = false
229+
) : array {
230+
$unique = array_unique($input, $sortFlags);
231+
if ($unique !== $input && $strict === true) {
232+
$duplicateValues = self::findDuplicates($input);
233+
throw new DuplicateValuesException($duplicateValues);
234+
}
235+
236+
return $unique;
237+
}
238+
239+
private static function findDuplicates(array $input) : array
240+
{
241+
$temp = [];
242+
$duplicates = [];
243+
foreach ($input as $key => $value) {
244+
if (!in_array($value, $temp, true)) {
245+
$temp[] = $value;
246+
continue;
247+
}
248+
249+
$duplicates[$key] = $value;
250+
}
251+
252+
return $duplicates;
253+
}
192254
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace TraderInteractive\Filter\Exceptions;
4+
5+
use TraderInteractive\Exceptions\FilterException;
6+
7+
class DuplicateValuesException extends FilterException
8+
{
9+
/**
10+
* @var string
11+
*/
12+
const ERROR_FORMAT = "Array contains the following duplicate values: %s";
13+
14+
/**
15+
* @param array $duplicateValues The duplicate values found in the array.
16+
*/
17+
public function __construct(array $duplicateValues)
18+
{
19+
$message = sprintf(self::ERROR_FORMAT, var_export($duplicateValues, true));
20+
parent::__construct($message);
21+
}
22+
}

tests/ArraysTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
use InvalidArgumentException;
66
use PHPUnit\Framework\TestCase;
77
use TraderInteractive\Exceptions\FilterException;
8+
use TraderInteractive\Filter\Exceptions\DuplicateValuesException;
89

910
/**
1011
* @coversDefaultClass \TraderInteractive\Filter\Arrays
12+
* @covers ::<private>
1113
*/
1214
final class ArraysTest extends TestCase
1315
{
@@ -240,4 +242,29 @@ public function padInvalidPadType()
240242
$this->expectExceptionMessage('Invalid $padType value provided');
241243
Arrays::pad(['a', 'b', 'c'], 5, null, 0);
242244
}
245+
246+
/**
247+
* @test
248+
* @covers ::unique
249+
*/
250+
public function unique()
251+
{
252+
$input = ['foo', 'bar', 'foo'];
253+
$filteredValue = Arrays::unique($input);
254+
$this->assertSame(['foo', 'bar'], $filteredValue);
255+
}
256+
257+
/**
258+
* @test
259+
* @covers ::unique
260+
*/
261+
public function uniqueStrict()
262+
{
263+
$input = ['foo', 'bar', 'foo'];
264+
$expectedDuplicates = ['2' => 'foo'];
265+
$expectedException = new DuplicateValuesException($expectedDuplicates);
266+
$this->expectException(DuplicateValuesException::class);
267+
$this->expectExceptionMessage($expectedException->getMessage());
268+
Arrays::unique($input, Arrays::ARRAY_UNIQUE_SORT_STRING, true);
269+
}
243270
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace Exceptions;
4+
5+
use PHPUnit\Framework\TestCase;
6+
use TraderInteractive\Filter\Exceptions\DuplicateValuesException;
7+
8+
/**
9+
* @coversDefaultClass \TraderInteractive\Filter\Exceptions\DuplicateValuesException
10+
*/
11+
final class DuplicateValuesExceptionTest extends TestCase
12+
{
13+
/**
14+
* @test
15+
* @covers ::__construct
16+
*/
17+
public function basicUsage()
18+
{
19+
$duplicates = ['foo', 'bar'];
20+
$exception = new DuplicateValuesException($duplicates);
21+
$this->assertSame(
22+
sprintf(DuplicateValuesException::ERROR_FORMAT, var_export($duplicates, true)),
23+
$exception->getMessage()
24+
);
25+
}
26+
}

0 commit comments

Comments
 (0)