LoginSignup
1
0

More than 1 year has passed since last update.

[PHP] CSVからスコア平均を求めてランキング化

Last updated at Posted at 2022-09-07

rana_kualuさんの記事を読んでたら、自分でもできそうな問題があったので挑戦。
PHPは長らく書いてなかったので、練習にはちょうど良い問題だった。

top10ranking.php
<?php

$file = $argv[1];

// 集計
foreach(csv($file) as [, $id, $score]){
    $player[$id] ??= ['total'=>0, 'count'=>0, 'id'=>$id];
    $player[$id]['total'] += $score;
    $player[$id]['count'] += 1;
}

// 平均点
foreach($player as $id => $v){
    $player[$id]['mean'] = round($v['total'] / $v['count']);
}

// 平均点とIDでソート
array_multisort(array_column($player, 'mean'), SORT_DESC, array_column($player, 'id'), SORT_ASC, $player);

// 順位
$all  = 1;
$prev = null;

foreach($player as $id => $v){
    if($v['mean'] !== $prev){
        $rank = $all;
    }
    $all++;
    $prev = $v['mean'];

    $player[$id]['rank'] = $rank;
}

// 出力
print "rank,player_id,mean_score\n";

foreach($player as $id => $v){
    if($v['rank'] > 10){
        break;
    }
    printf("%s,%s,%s\n", $v['rank'], $id, $v['mean']);
}


// CSVジェネレータ
function csv($file){
    $fp = fopen($file, 'r');
    fgetcsv($fp);

    while($line = fgetcsv($fp)){
        yield $line;
    }
}

最初は出力と同時に順位の計算を行っていたが、複雑になったので分離。
順位を計算するコードは書いたことがなかったので、検索して参考にした。
全プレイヤーの順位を計算してるのは無駄だが、最初はこんなものである。

それでもやはり、順位を求めるコードが汚いのはどうにかしたい所。
関数化するのが良いのかなあ?

ソート済みの配列を渡すと、順位を返すジェネレータ
function ranking(array $sorted){
    foreach($sorted as $i => $v){
        if($i === 0 or $v !== $sorted[$i-1]){
            $rank = $i + 1;
        }
        yield $rank;
    }
}
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0