Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel sort collection and then by key

Tags:

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)

like image 329
zarcel Avatar asked Apr 15 '15 08:04

zarcel


People also ask

How do I merge collections in laravel?

Laravel collection merge() method merge any given array to first collection array. If the first collection is indexed array, the second collection will be added to the end of the new collection. The merge() method can accept either an array or a Collection instance.


2 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);
like image 51
Needpoule Avatar answered Oct 01 '22 08:10

Needpoule


To sort a collection by key, you can sort the backing array by key 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);
    
    return $this;
    //to return a new instance
    //return collect($this->items);
 });

The last solution could be very useful if you are going to need to sort collections by key in many places in your code base

like image 34
Peter Chaula Avatar answered Oct 01 '22 08:10

Peter Chaula