Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

InspiredPrynce's avatar

Students Position From Average

Please i have a data like this..

array:9 [
    3101625668 => 98.0,
    3101635921 => 98.0,
    3913126364 => 35.77,
    3913058204 => 25.33,
    3101372540 => 33.47,
    3913752741 => 40.0,
    3913120054 => 20.4,
    3913998755 => 26.67,
    3913861492 => 25.2,
    3913881854 => 19.8,
]

I want to get the students position from the average. The array keys represent the student PIN Number and the value is their average. In array[0] and array[1], the values are the same and i want to get something like "1st" twice then "3rd"...

Someone help me please, have been awake all night working on this...

@andreasbakir thanks for the previous help you rendered! I appreciate man!

I really need help with this one!

0 likes
18 replies
InspiredPrynce's avatar

@Vilfago i would really appreciate it if you can show me a working example. I've been at it since, have sorted the shit outta this array. Please help...

Vilfago's avatar

Could you provide me the output you want ? An array with a sub-array containing pin and value ? Key as rank, or value for rank?

1 like
InspiredPrynce's avatar

@Vilfago i want an output like this..

array:10 [
    3101625668 => ["1st", 98.0],
    3101635921 => ["1st", 98.0],
    3913126364 => ["4th", 35.77],
    3913058204 => ["7th", 25.33],
    3101372540 => ["5th", 33.47],
    3913752741 => ["3rd", 40.0],
    3913120054 => ["9th", 20.4],
    3913998755 => ["6th", 26.67],
    3913861492 => ["8th", 25.2],
    3913881854 => ["10th", 19.8]
]
Vilfago's avatar
$results = collect([$array_results]);

$results_sorted = $results->sort()->reverse();

$current_rank = 1;
$number_in_position = 0;
$current_score = 100;

foreach($results_sorted as $pin => $result)
{
    if($result < $current_score){
        $current_score = $result;
        $current_rank += $number_in_position
        $number_in_position = 1;
        $output[$pin] = [$current_rank, $result];
        ++;
    }else{ //same score as the previous
        $number_in_position++;
        $output[$pin] = [$current_rank, $result];
    }
}

dd($output);

I didn't test it, I let you some job (test, debug, optimize)

1 like
burlresearch's avatar
    public function handle() {
        $marks = collect([3101625668 => 98.0, 3101635921 => 98.0, 3913126364 => 35.77, 3913058204 => 25.33, 3101372540 => 33.47, 3913752741 => 40.0, 3913120054 => 20.4, 3913998755 => 26.67, 3913861492 => 25.2, 3913881854 => 19.8,]);
        $avg  = $marks->avg();
        $rank = 1;

        $marks->sort()
            ->reverse()
            ->map(function ($mark, $id) use ($avg, &$rank) {
                return [
                    'dev'  => $mark - $avg,
                    'id'   => $id,
                    'mark' => $mark,
                    'rank' => $rank++,
                ];
            })
            ->dump();
        
        /* Illuminate\Support\Collection {
        array:10 [
          3101635921 => [
            "dev" => 55.736
            "id" => 3101635921
            "mark" => 98.0
            "rank" => 1
          ]
          3101625668 => [
            "dev" => 55.736
            "id" => 3101625668
            "mark" => 98.0
            "rank" => 2
          ]
          3913752741 => [
            "dev" => -2.264
            "id" => 3913752741
            "mark" => 40.0
            "rank" => 3
          ]
          3913126364 => [
            "dev" => -6.494
            "id" => 3913126364
            "mark" => 35.77
            "rank" => 4
          ]
          3101372540 => [
            "dev" => -8.794
            "id" => 3101372540
            "mark" => 33.47
            "rank" => 5
          ]
          3913998755 => [
            "dev" => -15.594
            "id" => 3913998755
            "mark" => 26.67
            "rank" => 6
          ]
          3913058204 => [
            "dev" => -16.934
            "id" => 3913058204
            "mark" => 25.33
            "rank" => 7
          ]
          3913861492 => [
            "dev" => -17.064
            "id" => 3913861492
            "mark" => 25.2
            "rank" => 8
          ]
          3913120054 => [
            "dev" => -21.864
            "id" => 3913120054
            "mark" => 20.4
            "rank" => 9
          ]
          3913881854 => [
            "dev" => -22.464
            "id" => 3913881854
            "mark" => 19.8
            "rank" => 10
          ]
        ]
        */
    }

Sorry, I missed the detail about resolving the ties. You'll have to do another pass over the collection to identify and score ties correctly.

1 like
InspiredPrynce's avatar

@burlresearch there is a slight issue here...

3913261052  10th    51.46
3913936730  9th             51.46

Aren't these two supposed to be 9th then the next one coming becomes 11th?

Vilfago's avatar

Yes... he told you he didn't do this part...

InspiredPrynce's avatar

@Vilfago there is an error in this


if($result < $current_score){
        $current_score = $result;
        $current_rank += $number_in_position
        $number_in_position = 1;
        $output[$pin] = [$current_rank, $result];

        ++; //What are you incrementing here?
    }
InspiredPrynce's avatar

@Vilfago here is the output


array:1 [▼
  0 => array:2 [▼
    0 => 1
    1 => array:21 [▼
      3913936730 => 28.0
      3913239999 => 21.73
      3913659614 => 22.0
      3913160091 => 19.47
      3913885329 => 29.73
      3913582846 => 30.27
      3913645641 => 15.4
      3913087292 => 23.73
      3913646349 => 14.93
      3913280872 => 21.87
      3913028769 => 13.6
      3913747249 => 26.8
      3913049985 => 22.4
      3913083105 => 25.07
      3913282411 => 40.0
      3913662799 => 39.87
      3913261052 => 20.67
      3913865578 => 9.2
      3913062432 => 17.73
      3913395866 => 35.6
      3913059859 => 34.0
    ]
  ]
]

Vilfago's avatar
Vilfago
Best Answer
Level 20
$array_results = [3101625668 => 98.0, 3101635921 => 98.0, 3913126364 => 35.77, 3913058204 => 25.33, 3101372540 => 33.47, 3913752741 => 40.0, 3913120054 => 20.4, 3913998755 => 26.67, 3913861492 => 25.2, 3913881854 => 19.8,];
        
        $results = collect($array_results);

        $results_sorted = $results->sort()->reverse();

        $current_rank = 1;
        $number_in_position = 0;

        $max_score = 100;
        $current_score = $max_score;

        foreach($results_sorted as $pin => $result)
        {
                if($result < $current_score ){
                        $current_score = $result;
                        $current_rank += $number_in_position;
                        $number_in_position = 1;
                        $output[$pin] = [$current_rank, $result];
                }else{ //same score as the previous
                        $number_in_position++;
                        $output[$pin] = [$current_rank, $result];
                }
        }

        dd($output);
1 like
burlresearch's avatar

Just for the record, here is a minor variation that does the ranking (with ties) in a single pass. Quite simple:

public function handle() {
    $marks = collect([3101625668 => 98.0, 3101635921 => 98.0, 3913126364 => 35.77, 3913058204 => 25.33, 3101372540 => 33.47, 3913752741 => 40.0, 3913120054 => 20.4, 3913998755 => 26.67, 3913861492 => 25.2, 3913881854 => 19.8,]);
    $avg   = $marks->avg();
    $rank  = 0;
    $run   = 0;
    $prev  = null;

    $marks->sort()
        ->reverse()
        ->map(function ($mark, $id) use ($avg, &$rank, &$run, &$prev) {
            $run  = $mark == $prev ? $run + 1 : 0;
            $prev = $mark;
            return [
                'mark' => $mark,
                'rank' => ++$rank - $run,
                'dev'  => $mark - $avg,
                'id'   => $id,
            ];
        })
        ->dump();
}
1 like
InspiredPrynce's avatar

@burlresearch wow! This is beautiful! Your function is quote nice and can easily be manipulated by yours truly! This is nice! Thanks man

Please or to participate in this conversation.