Ranking methods: Difference between revisions

(Added Wren)
Line 3,091:
5.0 41 Barry
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}}==
Anonymous user