Skip to content

Commit

Permalink
Merge pull request #28181 from timacdonald/collection_duplicates
Browse files Browse the repository at this point in the history
[5.8] Add duplicates method to collection
  • Loading branch information
taylorotwell authored Apr 11, 2019
2 parents 627fa08 + b86a424 commit 79a1cf5
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 0 deletions.
44 changes: 44 additions & 0 deletions src/Illuminate/Support/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,50 @@ public function diffKeysUsing($items, callable $callback)
return new static(array_diff_ukey($this->items, $this->getArrayableItems($items), $callback));
}

/**
* Retrieve duplicate items from the collection.
*
* @param callable|null $callback
* @param bool $strict
* @return static
*/
public function duplicates($callback = null, $strict = false)
{
$items = $this->map($this->valueRetriever($callback));

$uniqueItems = $items->unique(null, $strict);

$compare = $strict ? function ($a, $b) {
return $a === $b;
}
: function ($a, $b) {
return $a == $b;
};

$duplicates = new static;

foreach ($items as $key => $value) {
if ($uniqueItems->isNotEmpty() && $compare($value, $uniqueItems->first())) {
$uniqueItems->shift();
} else {
$duplicates[$key] = $value;
}
}

return $duplicates;
}

/**
* Retrieve duplicate items from the collection using strict comparison.
*
* @param callable|null $callback
* @return static
*/
public function duplicatesStrict($callback = null)
{
return $this->duplicates($callback, true);
}

/**
* Execute a callback over each item.
*
Expand Down
54 changes: 54 additions & 0 deletions tests/Support/SupportCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,60 @@ public function testDiffAssocUsing()
$this->assertEquals(['b' => 'brown', 'c' => 'blue', 'red'], $c1->diffAssocUsing($c2, 'strcasecmp')->all());
}

public function testDuplicates()
{
$duplicates = Collection::make([1, 2, 1, 'laravel', null, 'laravel', 'php', null])->duplicates()->all();
$this->assertSame([2 => 1, 5 => 'laravel', 7 => null], $duplicates);

// does loose comparison
$duplicates = Collection::make([2, '2', [], null])->duplicates()->all();
$this->assertSame([1 => '2', 3 => null], $duplicates);

// works with mix of primitives
$duplicates = Collection::make([1, '2', ['laravel'], ['laravel'], null, '2'])->duplicates()->all();
$this->assertSame([3 => ['laravel'], 5 => '2'], $duplicates);

// works with mix of objects and primitives **excepts numbers**.
$expected = new Collection(['laravel']);
$duplicates = Collection::make([new Collection(['laravel']), $expected, $expected, [], '2', '2'])->duplicates()->all();
$this->assertSame([1 => $expected, 2 => $expected, 5 => '2'], $duplicates);
}

public function testDuplicatesWithKey()
{
$items = [['framework' => 'vue'], ['framework' => 'laravel'], ['framework' => 'laravel']];
$duplicates = Collection::make($items)->duplicates('framework')->all();
$this->assertSame([2 => 'laravel'], $duplicates);
}

public function testDuplicatesWithCallback()
{
$items = [['framework' => 'vue'], ['framework' => 'laravel'], ['framework' => 'laravel']];
$duplicates = Collection::make($items)->duplicates(function ($item) {
return $item['framework'];
})->all();
$this->assertSame([2 => 'laravel'], $duplicates);
}

public function testDuplicatesWithStrict()
{
$duplicates = Collection::make([1, 2, 1, 'laravel', null, 'laravel', 'php', null])->duplicatesStrict()->all();
$this->assertSame([2 => 1, 5 => 'laravel', 7 => null], $duplicates);

// does strict comparison
$duplicates = Collection::make([2, '2', [], null])->duplicatesStrict()->all();
$this->assertSame([], $duplicates);

// works with mix of primitives
$duplicates = Collection::make([1, '2', ['laravel'], ['laravel'], null, '2'])->duplicatesStrict()->all();
$this->assertSame([3 => ['laravel'], 5 => '2'], $duplicates);

// works with mix of primitives, objects, and numbers
$expected = new Collection(['laravel']);
$duplicates = Collection::make([new Collection(['laravel']), $expected, $expected, [], '2', '2'])->duplicatesStrict()->all();
$this->assertSame([2 => $expected, 5 => '2'], $duplicates);
}

public function testEach()
{
$c = new Collection($original = [1, 2, 'foo' => 'bar', 'bam' => 'baz']);
Expand Down

0 comments on commit 79a1cf5

Please sign in to comment.