diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index 1c54424..f7bc4e8 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -1340,7 +1340,7 @@ public function sort(callable $callback = null) */ public function sortBy($callback, $options = SORT_REGULAR, $descending = false) { - $results = []; + list($values, $results) = [[], []]; $callback = $this->valueRetriever($callback); @@ -1348,16 +1348,19 @@ public function sortBy($callback, $options = SORT_REGULAR, $descending = false) // function which we were given. Then, we will sort the returned values and // and grab the corresponding values for the sorted keys from this array. foreach ($this->items as $key => $value) { - $results[$key] = $callback($value, $key); + $values[] = $callback($value, $key); } - $descending ? arsort($results, $options) - : asort($results, $options); + $keys = array_keys($this->items); + + $order = $descending ? SORT_DESC : SORT_ASC; + + array_multisort($values, $order, $options, $keys, $order); // Once we have sorted all of the keys in the array, we will loop through them // and grab the corresponding model so we can set the underlying items list // to the sorted version. Then we'll just return the collection instance. - foreach (array_keys($results) as $key) { + foreach ($keys as $key) { $results[$key] = $this->items[$key]; } diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 7903bfc..8822316 100644 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -795,7 +795,7 @@ public function testSortBy() public function testSortByString() { $data = new Collection([['name' => 'taylor'], ['name' => 'dayle']]); - $data = $data->sortBy('name'); + $data = $data->sortBy('name', SORT_STRING); $this->assertEquals([['name' => 'dayle'], ['name' => 'taylor']], array_values($data->all())); @@ -805,6 +805,45 @@ public function testSortByString() $this->assertEquals([['name' => 'dayle'], ['name' => 'taylor']], array_values($data->all())); } + public function testSortByMaintainsOriginalOrderOfItemsWithIdenticalValues() + { + $data = new Collection([['name' => 'taylor'], ['name' => 'dayle'], ['name' => 'dayle']]); + + $data = $data->sortBy('name'); + + $this->assertEquals([['name' => 'dayle'], ['name' => 'dayle'], ['name' => 'taylor']], array_values($data->all())); + $this->assertEquals([1, 2, 0], $data->keys()->all()); + } + + public function testSortByStringMaintainsOriginalOrderOfItemsWithIdenticalValues() + { + $data = new Collection([['name' => 'taylor'], ['name' => 'dayle'], ['name' => 'dayle']]); + + $data = $data->sortBy('name', SORT_STRING); + + $this->assertEquals([['name' => 'dayle'], ['name' => 'dayle'], ['name' => 'taylor']], array_values($data->all())); + $this->assertEquals([1, 2, 0], $data->keys()->all()); + } + + public function testSortByNumericMaintainsOriginalOrderOfItemsWithIdenticalValues() + { + $data = new Collection([['name' => '2'], ['name' => '1'], ['name' => '1']]); + $data = $data->sortBy('name', SORT_NUMERIC); + + $this->assertEquals([['name' => '1'], ['name' => '1'], ['name' => '2']], array_values($data->all())); + $this->assertEquals([1, 2, 0], $data->keys()->all()); + } + + public function testSortByNaturalMaintainsOriginalOrderOfItemsWithIdenticalValues() + { + $data = new Collection([['name' => 'img10.png'], ['name' => 'img1.png'], ['name' => 'img1.png']]); + + $data = $data->sortBy('name', SORT_NATURAL); + + $this->assertEquals([['name' => 'img1.png'], ['name' => 'img1.png'], ['name' => 'img10.png']], array_values($data->all())); + $this->assertEquals([1, 2, 0], $data->keys()->all()); + } + public function testSortByAlwaysReturnsAssoc() { $data = new Collection(['a' => 'taylor', 'b' => 'dayle']);