Home » Php » Laravel sort collection and then by key

Laravel sort collection and then by key

Posted by: admin November 29, 2017 Leave a comment

Questions:

I am making raking system for my users and here’s what I have so far:

Get all users and sort them by points – it works fine.

$users = User::all();
$users = $users->sortByDesc(function($item){
    return $item->points()->sum('amount');
});

Find your position in ranking – it works fine

$position = 0;
foreach($users as $user){
    if(Auth::user()->id == $user->id) break;
    $position++;
}

Get myself and users above/under me – it doesn’t work. I get random users. It looks like the collection is not sorted anymore.

$myRank = new Collection();
if($position > 9){
    $myRank->add($users->get($position-1));
    $myRank->add($users->get($position));
    $myRank->add($users->get($position+1));
    return view('rank.show', ['topTen' => $users->take(15), 'myRank' => $myRank]);
}

Please help me with this one or give some hint on another approach(light weight for many records)

Answers:

I think the problem is this:

When you call User::all() you get something like this:

0 => points: 10
1 => points: 50
2 => points: 30
3 => points: 70
4 => points: 20

Then you use the sortBy function, which reorder the collection, but does not reset the keys. So you end up with something like this:

3 => points: 70
1 => points: 50
2 => points: 30
4 => points: 20
0 => points: 10

So using position -1, position, and position +1 makes no sense here.

What you can do is using the values() function, which will reset the keys of you collection:

0 => points: 70
1 => points: 50
2 => points: 30
3 => points: 20
4 => points: 10

So I think the following code would work.

$users = User::all();
$users = $users->sortByDesc(function($item){
    return $item->points()->sum('amount');
})->values();

And then get 3 users from positions – 1 to position + 1:

$myRank = $users->splice($position - 1, 3);

Questions:
Answers:

To sort by key you can get the backing array then recreate the collection again.

$c = collect(['a' => 1, 'c' => 67, 'b' => 2]);
 $items = $c->all();
 ksort($items);

 $c = collect($items);

Or you can use a macro to get access to the backing array.

 Collection::macro('ksort', function(){
    //macros callbacks are bound to collection so we can safely access
    // protected Collection::items
    ksort($this->items);
 });

Questions:
Answers:

For any sorting array by key, I would suggest native PHP function ksort().