Making a dense_rank counter in PHP using array.
Covering why I need to do a dance rank in PHP not using MySQL. I be dealing with dynamic combinations 100,000 to 900 combinations per week, that’s why I cannot use MySQL to make that many tables.
The top part of the code deals with rank works no issue. The bottom part deals with dense_rank, issue is, if there are more than 2 combinations with the same number that is where enters the wrong number into the array.
The example array with the errors.
num | rank | dynamic rank |
---|---|---|
2 | 1 | 1 |
2 | 1 | 1 |
3 | 2 | 3 |
3 | 2 | 3 |
3 | 2 | 4 |
3 | 2 | 5 |
3 | 2 | 6 |
5 | 3 | 8 |
9 | 4 | 9 |
9 | 4 | 9 |
9 | 4 | 10 |
Notice when the error happens and there is a higher number in the number column it corrects the error in that row. See that when the number goes from 3 to 5.
PHP code
<?php
$members = array(
array(
'num' => 2,
'rank' => 0,
'dense_rank' => 0,
),
array(
'num' => 2,
'rank' => 0,
'dense_rank' => 0,
),
array(
'num' => 3,
'rank' => 0,
'dense_rank' => 0,
),
array(
'num' => 3,
'rank' => 0,
'dense_rank' => 0,
),
array(
'num' => 3,
'rank' => 0,
'dense_rank' => 0,
),
array(
'num' => 3,
'rank' => 0,
'dense_rank' => 0,
),
array(
'num' => 3,
'rank' => 0,
'dense_rank' => 0,
),
array(
'num' => 5,
'rank' => 0,
'dense_rank' => 0,
),
array(
'num' => 9,
'rank' => 0,
'dense_rank' => 0,
),
array(
'num' => 9,
'rank' => 0,
'dense_rank' => 0,
),
array(
'num' => 9,
'rank' => 0,
'dense_rank' => 0,
)
);
$rank=0;
$previous_rank=0;
$dense_rank=0;
$previous_dense_rank=0;
foreach($members as &$var){
//star of rank
if($var['num']==$previous_rank){
$var['rank']=$rank;
}else{
$var['rank']= $rank;
$previous_rank=$var['num'];
}//end of rank
//star of rank_dense
if($var['num']===$previous_dense_rank){
$var['dense_rank']=$dense_rank;
$dense_rank;
}else{
$var['dense_rank']= $dense_rank;
$previous_dense_rank=$var['num'];
}
//end of rank_dense
echo $var['num'].' - '.$var['rank'].' - '.$var['dense_rank'].'<br>';
}
?>
Thank you for your help.
CodePudding user response:
It seems like you want the dynamic rank to be sequential?
Your sample data appears to be sorted, if this remains true for your real data then you can remove the conditional and just increment the variable as you assign it:
//start of rank_dense
$var['dense_rank']= $dense_rank;
//end of rank_dense
It sounds like you're saying you won't be implementing a database. Databases like MySQL can easily handle the workload numbers you outlined and they can sort your data as well. You may want to reconsider.
CodePudding user response:
Given that your results are already sorted in an ascending fashion...
For dense ranking, you need to only increment your counter when a new score is encountered.
For gapped ranking, you need to unconditionally increment your counter and use the counter value for all members with the same score.
??=
is the "null coalescing assignment" operator (a breed of "combined operator"). It only allows the right side operand to be executed/used if the left side operand is not declared or is null
. This is a technique of performing conditional assignments without needing to write a classic if
condition.
Code: (Demo)
$denseRank = 0;
$gappedRank = 0;
foreach ($members as &$row) {
$denseRanks[$row['num']] ??= $denseRank;
$row['dense_rank'] = $denseRanks[$row['num']];
$gappedRank;
$gappedRanks[$row['num']] ??= $gappedRank;
$row['rank'] = $gappedRanks[$row['num']];
// for better presentation:
echo json_encode($row) . "\n";
}
Output:
{"num":2,"rank":1,"dense_rank":1}
{"num":2,"rank":1,"dense_rank":1}
{"num":3,"rank":3,"dense_rank":2}
{"num":3,"rank":3,"dense_rank":2}
{"num":3,"rank":3,"dense_rank":2}
{"num":3,"rank":3,"dense_rank":2}
{"num":3,"rank":3,"dense_rank":2}
{"num":5,"rank":8,"dense_rank":3}
{"num":9,"rank":9,"dense_rank":4}
{"num":9,"rank":9,"dense_rank":4}
{"num":9,"rank":9,"dense_rank":4}
For the record, if you are dealing with huge volumes of data, I would be using SQL instead of PHP for this task.