ランキングで何位になるか調べる
たとえばゲームの得点ランキングがあり、あるプレイヤの得点が何位になるか調べたい場合があります。
bisectモジュールを使えば、ある値が得点リストの何番目に入るのか調べることができます。
from bisect import bisect ranking = [116, 151, 98] ranking.sort() x = 143 i = bisect(ranking, x) ranking.insert(i, x) print '%d位 ... %d' % (len(ranking)-i+1, x) print reversed(ranking)
2位 ... 143 [151, 143, 116, 98]
bisectはリストが小さい方から順番にソートされていないと使えません。得点リストは低い順にしておき、順位を表示するときに補正します。
順位を出したら得点ランキングに新しい得点を追加します。bisectの返す値をそのままinsertの挿入位置の指定に使います。このように挿入すればrankingはソートされた状態を維持できるので、再度ranking.sort()を行う必要はありません。
同点のときの処理
もしこの得点ランキングで、別の人が同じ得点を取った場合どうなるでしょうか。
x = 143 i = bisect(ranking, x) ranking.insert(i, x) print '%d位 ... %d' % (len(ranking)-i+1, x) print reversed(ranking)
2位 ... 143 [151, 143, 143, 116, 98]
bisectはbisect_rightという関数の別名です。これは同じ値があればその右側に挿入する位置を返します。その逆にbisect_leftがあり、これは左側の挿入位置を返します。
この得点ランキングは低い方から点数を並べているので、右側=順位が高い、となります。このため後から143点を取った人も同じく2位となります。おそらくほとんどのゲームは同点なら同順位のはずなので問題ないはずです。
このことはつまり、得点を追加するときに限らず、x点を取った人が何位なのか、いつでも調べることができるということです。この場合insertは使わず、単にbisectをかけるだけです。
x = 116 i = bisect(ranking, x) print '%d位 ... %d' % (len(ranking)-i+1, x)
4位 ... 116
得点の少ないほうが勝ちというゲームの場合
得点が少ないほうが上位になるというゲームもあります。この場合も、bisectの代わりにbisect_leftを使い、表示をちょっと変更するだけで、ほとんど同じように対応できます。
from bisect import bisect_left ranking = [116, 151, 98] ranking.sort() x = 143 i = bisect_left(ranking, x) ranking.insert(i, x) print '%d位 ... %d' % (i+1, x) print ranking
3位 ... 143 [98, 116, 143, 151]