Ranking methods: Difference between revisions
Content added Content deleted
(Added Wren) |
|||
Line 3,091: | Line 3,091: | ||
5.0 41 Barry |
5.0 41 Barry |
||
7.0 39 Stephen</pre> |
7.0 39 Stephen</pre> |
||
=={{header|Nim}}== |
|||
To simplify, it’s convenient to build a table giving for each score the list of competitor name. |
|||
<lang Nim>import algorithm, sequtils, stats, tables |
|||
type |
|||
Record = tuple[score: int; name: string] # Input data. |
|||
Groups = OrderedTable[int, seq[string]] # Maps score to list of names. |
|||
Rank = tuple[rank: int; name: string; score: int] # Result. |
|||
FractRank = tuple[rank: float; name: string; score: int] # Result (fractional). |
|||
func cmp(a, b: (int, seq[string])): int = |
|||
## Comparison function needed to sort the groups. |
|||
cmp(a[0], b[0]) |
|||
func toGroups(records: openArray[Record]): Groups = |
|||
## Build a "Groups" table from the records. |
|||
for record in records: |
|||
result.mgetOrPut(record.score, @[]).add record.name |
|||
# Sort the list of names by alphabetic order. |
|||
for score in result.keys: |
|||
sort(result[score]) |
|||
# Sort the groups by decreasing score. |
|||
result.sort(cmp, Descending) |
|||
func standardRanks(groups: Groups): seq[Rank] = |
|||
var rank = 1 |
|||
for score, names in groups.pairs: |
|||
for name in names: |
|||
result.add (rank, name, score) |
|||
inc rank, names.len |
|||
func modifiedRanks(groups: Groups): seq[Rank] = |
|||
var rank = 0 |
|||
for score, names in groups.pairs: |
|||
inc rank, names.len |
|||
for name in names: |
|||
result.add (rank, name, score) |
|||
func denseRanks(groups: Groups): seq[Rank] = |
|||
var rank = 0 |
|||
for score, names in groups.pairs: |
|||
inc rank |
|||
for name in names: |
|||
result.add (rank, name, score) |
|||
func ordinalRanks(groups: Groups): seq[Rank] = |
|||
var rank = 0 |
|||
for score, names in groups.pairs: |
|||
for name in names: |
|||
inc rank |
|||
result.add (rank, name, score) |
|||
func fractionalRanks(groups: Groups): seq[FractRank] = |
|||
var rank = 1 |
|||
for score, names in groups.pairs: |
|||
let fRank = mean(toSeq(rank..(rank + names.high))) |
|||
for name in names: |
|||
result.add (fRank, name, score) |
|||
inc rank, names.len |
|||
when isMainModule: |
|||
const Data = [(44, "Solomon"), (42, "Jason"), (42, "Errol"), |
|||
(41, "Garry"), (41, "Bernard"), (41, "Barry"), (39, "Stephen")] |
|||
let groups = Data.toGroups() |
|||
echo "Standard ranking:" |
|||
for (rank, name, score) in groups.standardRanks(): |
|||
echo rank, ": ", name, " ", score |
|||
echo() |
|||
echo "Modified ranking:" |
|||
for (rank, name, score) in groups.modifiedRanks(): |
|||
echo rank, ": ", name, " ", score |
|||
echo() |
|||
echo "Dense ranking:" |
|||
for (rank, name, score) in groups.denseRanks(): |
|||
echo rank, ": ", name, " ", score |
|||
echo() |
|||
echo "Ordinal ranking:" |
|||
for (rank, name, score) in groups.ordinalRanks(): |
|||
echo rank, ": ", name, " ", score |
|||
echo() |
|||
echo "Fractional ranking:" |
|||
for (rank, name, score) in groups.fractionalRanks(): |
|||
echo rank, ": ", name, " ", score</lang> |
|||
{{out}} |
|||
<pre>Standard ranking: |
|||
1: Solomon 44 |
|||
2: Errol 42 |
|||
2: Jason 42 |
|||
4: Barry 41 |
|||
4: Bernard 41 |
|||
4: Garry 41 |
|||
7: Stephen 39 |
|||
Modified ranking: |
|||
1: Solomon 44 |
|||
3: Errol 42 |
|||
3: Jason 42 |
|||
6: Barry 41 |
|||
6: Bernard 41 |
|||
6: Garry 41 |
|||
7: Stephen 39 |
|||
Dense ranking: |
|||
1: Solomon 44 |
|||
2: Errol 42 |
|||
2: Jason 42 |
|||
3: Barry 41 |
|||
3: Bernard 41 |
|||
3: Garry 41 |
|||
4: Stephen 39 |
|||
Ordinal ranking: |
|||
1: Solomon 44 |
|||
2: Errol 42 |
|||
3: Jason 42 |
|||
4: Barry 41 |
|||
5: Bernard 41 |
|||
6: Garry 41 |
|||
7: Stephen 39 |
|||
Fractional ranking: |
|||
1.0: Solomon 44 |
|||
2.5: Errol 42 |
|||
2.5: Jason 42 |
|||
5.0: Barry 41 |
|||
5.0: Bernard 41 |
|||
5.0: Garry 41 |
|||
7.0: Stephen 39</pre> |
|||
But it is possible to do the ranking without this auxiliary table. |
|||
<lang Nim>import algorithm |
|||
type |
|||
Record = tuple[score: int; name: string] # Input data. |
|||
Rank = tuple[rank: int; name: string; score: int] # Result. |
|||
FractRank = tuple[rank: float; name: string; score: int] # Result (fractional). |
|||
func cmp(a, b: Record): int = |
|||
## Record comparison function (needed for sorting). |
|||
result = cmp(b[0], a[0]) # Reverse order. |
|||
if result == 0: |
|||
result = cmp(a.name, b.name) # Alphabetical order. |
|||
func standardRanks(records: openArray[Record]): seq[Rank] = |
|||
let records = sorted(records, cmp) |
|||
var rank = 1 |
|||
var currScore = records[0].score |
|||
for idx, (score, name) in records: |
|||
if score != currScore: |
|||
rank = idx + 1 |
|||
currScore = score |
|||
result.add (rank, name, score) |
|||
func modifiedRanks(records: openArray[Record]): seq[Rank] = |
|||
let records = sorted(records, cmp) |
|||
var rank = records.len |
|||
var currScore = records[^1].score |
|||
for idx in countdown(records.high, 0): |
|||
let (score, name) = records[idx] |
|||
if score != currScore: |
|||
rank = idx + 1 |
|||
currScore = score |
|||
result.add (rank, name, score) |
|||
result.reverse() |
|||
func denseRanks(records: openArray[Record]): seq[Rank] = |
|||
let records = sorted(records, cmp) |
|||
var rank = 1 |
|||
var currScore = records[0].score |
|||
for (score, name) in records: |
|||
if score != currScore: |
|||
inc rank |
|||
currScore = score |
|||
result.add (rank, name, score) |
|||
func ordinalRanks(records: openArray[Record]): seq[Rank] = |
|||
let records = sorted(records, cmp) |
|||
var rank = 0 |
|||
for (score, name) in records: |
|||
inc rank |
|||
result.add (rank, name, score) |
|||
func fractionalRanks(records: openArray[Record]): seq[FractRank] = |
|||
let records = sorted(records, cmp) |
|||
# Build a list of ranks. |
|||
var currScore = records[0].score |
|||
var sum = 0 |
|||
var ranks: seq[float] |
|||
var count = 0 |
|||
for idx, record in records: |
|||
if record.score == currScore: |
|||
inc count |
|||
inc sum, idx + 1 |
|||
else: |
|||
ranks.add sum / count |
|||
count = 1 |
|||
currScore = record.score |
|||
sum = idx + 1 |
|||
ranks.add sum / count |
|||
# Give a rank to each record. |
|||
currScore = records[0].score |
|||
var rankIndex = 0 |
|||
for (score, name) in records: |
|||
if score != currScore: |
|||
inc rankIndex |
|||
currScore = score |
|||
result.add (ranks[rankIndex], name, score) |
|||
when isMainModule: |
|||
const Data = [(44, "Solomon"), (42, "Jason"), (42, "Errol"), |
|||
(41, "Garry"), (41, "Bernard"), (41, "Barry"), (39, "Stephen")] |
|||
echo "Standard ranking:" |
|||
for (rank, name, score) in Data.standardRanks(): |
|||
echo rank, ": ", name, " ", score |
|||
echo() |
|||
echo "Modified ranking:" |
|||
for (rank, name, score) in Data.modifiedRanks(): |
|||
echo rank, ": ", name, " ", score |
|||
echo() |
|||
echo "Dense ranking:" |
|||
for (rank, name, score) in Data.denseRanks(): |
|||
echo rank, ": ", name, " ", score |
|||
echo() |
|||
echo "Ordinal ranking:" |
|||
for (rank, name, score) in Data.ordinalRanks(): |
|||
echo rank, ": ", name, " ", score |
|||
echo() |
|||
echo "Fractional ranking:" |
|||
for (rank, name, score) in Data.fractionalRanks(): |
|||
echo rank, ": ", name, " ", score</lang> |
|||
{{out}} |
|||
<pre>Same output as with other version.</pre> |
|||
=={{header|PARI/GP}}== |
=={{header|PARI/GP}}== |