Reputation: 122
I'm trying to create a list of users on a leaderboard.
In my case I have users with the same amount of points, and with this I would like to skip over the next x amount of ranks see below:
i.e
Position | Points
1 100
2 50
2 50
3 30
4 20
4 20
6 10
I've looked almost everywhere at an example of this and the closet I could find was this SO answer But they seem to have done half the job where they don't display the second (2) position or the second 5th and I need to show all the positions.
Here is my code (I tried removing values() like the other answer but it just makes the $key into the points value)
$ranks = $bets->groupBy('user_id')
->transform(function ($userGroup) {
// Set initial points value.
$points = 0;
// Map over the user group.
$userGroup->map(function ($user) use (&$points) {
// Assign points.
$points = $points + $user->points;
});
// Set the first users points format.
$userGroup->first()->user->points = number_format((float) $points, 2, '.', '');
// Return the first user.
return $userGroup->first()->user;
})
->sortByDesc('points')->groupBy('points')
->values()
->transform(function ($userGroup, $key) {
// Return the transformed usergroup.
return $userGroup->transform(function ($user) use ($key) {
// Set the user's position.
$user->position = $key + 1;
// Return the user.
return $user;
});
})
Current output
collection
array
0 => usercollection
0 => usercollection (position = 1)
1 => usercollection
0 => usercollection (position = 2)
1 => usercollection (position = 2)
2 => usercollection
0 => usercollection (position = 3)
3 => usercollection
0 => usercollection (position = 4)
1 => usercollection (position = 4)
4 => usercollection
0 => usercollection (position = 5)
Expected outcome
collection
array
0 => usercollection
0 => usercollection (position = 1)
1 => usercollection
0 => usercollection (position = 2)
1 => usercollection (position = 2)
2 => usercollection
0 => usercollection (position = 4)
3 => usercollection
0 => usercollection (position = 5)
1 => usercollection (position = 5)
4 => usercollection
0 => usercollection (position = 6)
Upvotes: 0
Views: 188
Reputation: 46
You can use the chunkWhile function like this
$collection = collect([
['position' => 1, 'point' => 100,],
['position' => 2, 'point' => 90,],
['position' => 2, 'point' => 90,],
['position' => 3, 'point' => 80,],
['position' => 4, 'point' => 70,],
['position' => 4, 'point' => 70,],
['position' => 5, 'point' => 60,],
]);
$collection = $collection->chunkWhile(function ($item, $key, $chunk){
return $item['point'] === $chunk->last()['point'];
});
Result :
collect(
collect(
['position' => 1, 'point' => 100,],
),
collect(
['position' => 2, 'point' => 90,],
['position' => 2, 'point' => 90,],
),
collect(
['position' => 3, 'point' => 80,],
),
collect(
['position' => 4, 'point' => 70,],
['position' => 4, 'point' => 70,],
),
collect(
['position' => 5, 'point' => 60,],
)
);
Upvotes: 1