Skip to content

Commit

Permalink
Merge branch 'johnylemon/8.x' into 8.x
Browse files Browse the repository at this point in the history
  • Loading branch information
taylorotwell committed Nov 19, 2020
2 parents c054535 + 53eb307 commit 5ba7984
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/Illuminate/Collections/Arr.php
Expand Up @@ -604,7 +604,7 @@ public static function shuffle($array, $seed = null)
* Sort the array using the given callback or "dot" notation.
*
* @param array $array
* @param callable|string|null $callback
* @param callable|array|string|null $callback
* @return array
*/
public static function sort($array, $callback = null)
Expand Down
50 changes: 49 additions & 1 deletion src/Illuminate/Collections/Collection.php
Expand Up @@ -1110,13 +1110,17 @@ public function sortDesc($options = SORT_REGULAR)
/**
* Sort the collection using the given callback.
*
* @param callable|string $callback
* @param callable|array|string $callback
* @param int $options
* @param bool $descending
* @return static
*/
public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
{
if (is_array($callback)) {
return $this->sortByMany($callback);
}

$results = [];

$callback = $this->valueRetriever($callback);
Expand All @@ -1141,6 +1145,50 @@ public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
return new static($results);
}

/**
* Sort the collection using multiple comparisons.
*
* @param array $comparisons
* @return static
*/
protected function sortByMany(array $comparisons = [])
{
$items = $this->items;

usort($items, function ($a, $b) use ($comparisons) {
foreach ($comparisons as $comparison) {
$comparison = Arr::wrap($comparison);

$prop = $comparison[0];

$ascending = Arr::get($comparison, 1, true) === true ||
Arr::get($comparison, 1, true) === 'asc';

$result = 0;

if (is_callable($prop)) {
$result = $prop($a, $b);
} else {
$values = [Arr::get($a, $prop), Arr::get($b, $prop)];

if (! $ascending) {
$values = array_reverse($values);
}

$result = $values[0] <=> $values[1];
}

if ($result === 0) {
continue;
}

return $result;
}
});

return new static($items);
}

/**
* Sort the collection in descending order using the given callback.
*
Expand Down
53 changes: 53 additions & 0 deletions tests/Support/SupportArrTest.php
Expand Up @@ -903,4 +903,57 @@ public function testWrap()
$this->assertEquals([$obj], Arr::wrap($obj));
$this->assertSame($obj, Arr::wrap($obj)[0]);
}

public function testSortByMany()
{
$unsorted = [
['name' => 'John', 'age' => 8, 'meta' => ['key' => 3]],
['name' => 'John', 'age' => 10, 'meta' => ['key' => 5]],
['name' => 'Dave', 'age' => 10, 'meta' => ['key' => 3]],
['name' => 'John', 'age' => 8, 'meta' => ['key' => 2]],
];

// sort using keys
$sorted = array_values(Arr::sort($unsorted, [
'name',
'age',
'meta.key',
]));
$this->assertEquals([
['name' => 'Dave', 'age' => 10, 'meta' => ['key' => 3]],
['name' => 'John', 'age' => 8, 'meta' => ['key' => 2]],
['name' => 'John', 'age' => 8, 'meta' => ['key' => 3]],
['name' => 'John', 'age' => 10, 'meta' => ['key' => 5]],
], $sorted);

// sort with order
$sortedWithOrder = array_values(Arr::sort($unsorted, [
'name',
['age', false],
['meta.key', true],
]));
$this->assertEquals([
['name' => 'Dave', 'age' => 10, 'meta' => ['key' => 3]],
['name' => 'John', 'age' => 10, 'meta' => ['key' => 5]],
['name' => 'John', 'age' => 8, 'meta' => ['key' => 2]],
['name' => 'John', 'age' => 8, 'meta' => ['key' => 3]],
], $sortedWithOrder);

// sort using callable
$sortedWithCallable = array_values(Arr::sort($unsorted, [
function ($a, $b) {
return $a['name'] <=> $b['name'];
},
function ($a, $b) {
return $b['age'] <=> $a['age'];
},
['meta.key', true],
]));
$this->assertEquals([
['name' => 'Dave', 'age' => 10, 'meta' => ['key' => 3]],
['name' => 'John', 'age' => 10, 'meta' => ['key' => 5]],
['name' => 'John', 'age' => 8, 'meta' => ['key' => 2]],
['name' => 'John', 'age' => 8, 'meta' => ['key' => 3]],
], $sortedWithCallable);
}
}

0 comments on commit 5ba7984

Please sign in to comment.