Update all new Tasks

This commit is contained in:
Ingy döt Net 2015-02-20 09:02:09 -05:00
parent 00a190b0a6
commit 91df62d461
5697 changed files with 93386 additions and 804 deletions

View file

@ -0,0 +1,23 @@
The numerical rank of competitors in a competition shows if one is better than, equal to, or worse than another based on their results in a competition.
The numerical rank of a competitor can be assigned in several [[wp:Ranking|different ways]].
;Task:
The following scores are accrued for all competitors of a competition (in best-first order):
<pre>44 Solomon
42 Jason
42 Errol
41 Garry
41 Bernard
41 Barry
39 Stephen</pre>
For each of the following ranking methods, create a function/method/procedure/subroutine... that applies the ranking method to an ordered list of scores with scorers:
# Standard. (Ties share what would have been their first ordinal number).
# Modified. (Ties share what would have been their last ordinal number).
# Dense. (Ties share the next available integer).
# Ordinal. ((Competitors take the next available integer. Ties are not treated otherwise).
# Fractional. (Ties share the mean of what would have been their ordinal numbers).
See the [[wp:Ranking|wikipedia article]] for a fuller description.
Show here, on this page, the ranking of the test scores under each of the numbered ranking methods.

View file

@ -0,0 +1,100 @@
##
## Dense ranking in file: ranking_d.awk
##
BEGIN{ lastresult = "!"; lastrank = 0 }
function d_rank(){
if($1==lastresult){
print lastrank, $0
}else{
lastresult = $1
print ++lastrank, $0 }
}
//{d_rank() }
##
## Fractional ranking in file: ranking_f.awk
##
BEGIN{
last = "!"
flen = 0 }
function f_rank(){
item = $0
if($1!=last){
if(flen){
sum = 0
for(fl=0; fl < flen;){
$0 = fifo[fl++]
sum += $1 }
mean = sum / flen
for(fl=0; fl < flen;){
$0 = fifo[fl++]
$1 = ""
printf("%3g %s\n", mean, $0) }
flen = 0
}}
$0 = item
last = $1
fifo[flen++] = sprintf("%i %s", FNR, item)
}
//{f_rank()}
END{ if(flen){
sum = 0
for(fl=0; fl < flen;){
$0 = fifo[fl++]
sum += $1 }
mean = sum / flen
for(fl=0; fl < flen;){
$0 = fifo[fl++]
$1 = ""
printf("%3g %s\n", mean, $0) }}}
##
## Modified competition ranking in file: ranking_mc.awk
##
BEGIN{
lastresult = "!"
flen = 0 }
function mc_rank(){
if($1==lastresult){
fifo[flen++] = $0
}else{
for(fl=0; fl < flen;){
print FNR-1, fifo[fl++]}
flen = 0
fifo[flen++] = $0
lastresult = $1}
}
//{mc_rank()}
END{ for(fl=0; fl < flen;){
print FNR, fifo[fl++]} }
##
## Ordinal ranking in file: ranking_o.awk
##
function o_rank(){ print FNR, $0 }
//{o_rank() }
##
## Standard competition ranking in file: ranking_sc.awk
##
BEGIN{ lastresult = lastrank = "!" }
function sc_rank(){
if($1==lastresult){
print lastrank, $0
}else{
print FNR, $0
lastresult = $1
lastrank = FNR}
}
//{sc_rank()}

View file

@ -0,0 +1,113 @@
package main
import (
"fmt"
"sort"
)
type rankable interface {
Len() int
RankEqual(int, int) bool
}
func StandardRank(d rankable) []float64 {
r := make([]float64, d.Len())
var k int
for i := range r {
if i == 0 || !d.RankEqual(i, i-1) {
k = i + 1
}
r[i] = float64(k)
}
return r
}
func ModifiedRank(d rankable) []float64 {
r := make([]float64, d.Len())
for i := range r {
k := i + 1
for j := i + 1; j < len(r) && d.RankEqual(i, j); j++ {
k = j + 1
}
r[i] = float64(k)
}
return r
}
func DenseRank(d rankable) []float64 {
r := make([]float64, d.Len())
var k int
for i := range r {
if i == 0 || !d.RankEqual(i, i-1) {
k++
}
r[i] = float64(k)
}
return r
}
func OrdinalRank(d rankable) []float64 {
r := make([]float64, d.Len())
for i := range r {
r[i] = float64(i + 1)
}
return r
}
func FractionalRank(d rankable) []float64 {
r := make([]float64, d.Len())
for i := 0; i < len(r); {
var j int
f := float64(i + 1)
for j = i + 1; j < len(r) && d.RankEqual(i, j); j++ {
f += float64(j + 1)
}
f /= float64(j - i)
for ; i < j; i++ {
r[i] = f
}
}
return r
}
type scores []struct {
score int
name string
}
func (s scores) Len() int { return len(s) }
func (s scores) RankEqual(i, j int) bool { return s[i].score == s[j].score }
func (s scores) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s scores) Less(i, j int) bool {
if s[i].score != s[j].score {
return s[i].score > s[j].score
}
return s[i].name < s[j].name
}
var data = scores{
{44, "Solomon"},
{42, "Jason"},
{42, "Errol"},
{41, "Garry"},
{41, "Bernard"},
{41, "Barry"},
{39, "Stephen"},
}
func main() {
show := func(name string, fn func(rankable) []float64) {
fmt.Println(name, "Ranking:")
r := fn(data)
for i, d := range data {
fmt.Printf("%4v - %2d %s\n", r[i], d.score, d.name)
}
}
sort.Sort(data)
show("Standard", StandardRank)
show("\nModified", ModifiedRank)
show("\nDense", DenseRank)
show("\nOrdinal", OrdinalRank)
show("\nFractional", FractionalRank)
}

View file

@ -0,0 +1,72 @@
import Data.List (groupBy, sort, intercalate)
type Item = (Int, String)
type ItemList = [Item]
type ItemGroups = [ItemList]
type RankItem a = (a, Int, String)
type RankItemList a = [RankItem a]
-- make sure the input is ordered and grouped by score
prepare :: ItemList -> ItemGroups
prepare = groupBy gf . reverse . sort
where gf (a, _) (b, _) = a == b
-- give an item a rank
rank :: Num a => a -> Item -> RankItem a
rank n (a, b) = (n, a, b)
-- ranking methods
standard, modified, dense, ordinal :: ItemGroups -> RankItemList Int
standard = ms 1 where
ms _ [] = []
ms n (x:xs) = map (rank n) x ++ ms (n + length x) xs
modified = md 1 where
md _ [] = []
md n (x:xs) = let l = length x
nl = n + l
nl1 = nl - 1
in map (rank nl1) x ++ md (n + l) xs
dense = md 1 where
md _ [] = []
md n (x:xs) = map (rank n) x ++ md (n + 1) xs
ordinal = zipWith rank [1..] . concat
fractional :: ItemGroups -> RankItemList Double
fractional = mf 1.0 where
mf _ [] = []
mf n (x:xs) = let l = length x
o = take l [n ..]
ld = fromIntegral l
a = sum o / ld
in map (rank a) x ++ mf (n + ld) xs
-- sample data
test :: ItemGroups
test = prepare
[ (44, "Solomon")
, (42, "Jason")
, (42, "Errol")
, (41, "Garry")
, (41, "Bernard")
, (41, "Barry")
, (39, "Stephen") ]
-- print rank items nicely
nicePrint :: Show a => String -> RankItemList a -> IO ()
nicePrint xs items = do
putStrLn xs
mapM_ np items
putStr "\n"
where np (a, b, c) = putStrLn $ intercalate "\t" [show a, show b, c]
main :: IO ()
main = do
nicePrint "Standard:" $ standard test
nicePrint "Modified:" $ modified test
nicePrint "Dense:" $ dense test
nicePrint "Ordinal:" $ ordinal test
nicePrint "Fractional:" $ fractional test

View file

@ -0,0 +1,19 @@
competitors=:<;._1;._2]0 :0
44 Solomon
42 Jason
42 Errol
41 Garry
41 Bernard
41 Barry
39 Stephen
)
scores=: {."1
standard=: 1+i.~
modified=: 1+i:~
dense=: #/.~ # #\@~.
ordinal=: #\
fractional=: #/.~ # ] (+/%#)/. #\
rank=:1 :'<"0@u@:scores,.]'

View file

@ -0,0 +1,80 @@
standard rank competitors
┌─┬──┬───────┐
│1│44│Solomon│
├─┼──┼───────┤
│2│42│Jason │
├─┼──┼───────┤
│2│42│Errol │
├─┼──┼───────┤
│4│41│Garry │
├─┼──┼───────┤
│4│41│Bernard│
├─┼──┼───────┤
│4│41│Barry │
├─┼──┼───────┤
│7│39│Stephen│
└─┴──┴───────┘
modified rank competitors
┌─┬──┬───────┐
│1│44│Solomon│
├─┼──┼───────┤
│3│42│Jason │
├─┼──┼───────┤
│3│42│Errol │
├─┼──┼───────┤
│6│41│Garry │
├─┼──┼───────┤
│6│41│Bernard│
├─┼──┼───────┤
│6│41│Barry │
├─┼──┼───────┤
│7│39│Stephen│
└─┴──┴───────┘
dense rank competitors
┌─┬──┬───────┐
│1│44│Solomon│
├─┼──┼───────┤
│2│42│Jason │
├─┼──┼───────┤
│2│42│Errol │
├─┼──┼───────┤
│3│41│Garry │
├─┼──┼───────┤
│3│41│Bernard│
├─┼──┼───────┤
│3│41│Barry │
├─┼──┼───────┤
│4│39│Stephen│
└─┴──┴───────┘
ordinal rank competitors
┌─┬──┬───────┐
│1│44│Solomon│
├─┼──┼───────┤
│2│42│Jason │
├─┼──┼───────┤
│3│42│Errol │
├─┼──┼───────┤
│4│41│Garry │
├─┼──┼───────┤
│5│41│Bernard│
├─┼──┼───────┤
│6│41│Barry │
├─┼──┼───────┤
│7│39│Stephen│
└─┴──┴───────┘
fractional rank competitors
┌───┬──┬───────┐
│1 │44│Solomon│
├───┼──┼───────┤
│2.5│42│Jason │
├───┼──┼───────┤
│2.5│42│Errol │
├───┼──┼───────┤
│5 │41│Garry │
├───┼──┼───────┤
│5 │41│Bernard│
├───┼──┼───────┤
│5 │41│Barry │
├───┼──┼───────┤
│7 │39│Stephen│
└───┴──┴───────┘

View file

@ -0,0 +1,75 @@
import java.util.*;
public class RankingMethods {
final static String[] input = {"44 Solomon", "42 Jason", "42 Errol",
"41 Garry", "41 Bernard", "41 Barry", "39 Stephen"};
public static void main(String[] args) {
int len = input.length;
Map<String, int[]> map = new TreeMap<>((a, b) -> b.compareTo(a));
for (int i = 0; i < len; i++) {
String key = input[i].split("\\s+")[0];
int[] arr;
if ((arr = map.get(key)) == null)
arr = new int[]{i, 0};
arr[1]++;
map.put(key, arr);
}
int[][] groups = map.values().toArray(new int[map.size()][]);
standardRanking(len, groups);
modifiedRanking(len, groups);
denseRanking(len, groups);
ordinalRanking(len);
fractionalRanking(len, groups);
}
private static void standardRanking(int len, int[][] groups) {
System.out.println("\nStandard ranking");
for (int i = 0, rank = 0, group = 0; i < len; i++) {
if (group < groups.length && i == groups[group][0]) {
rank = i + 1;
group++;
}
System.out.printf("%d %s%n", rank, input[i]);
}
}
private static void modifiedRanking(int len, int[][] groups) {
System.out.println("\nModified ranking");
for (int i = 0, rank = 0, group = 0; i < len; i++) {
if (group < groups.length && i == groups[group][0])
rank += groups[group++][1];
System.out.printf("%d %s%n", rank, input[i]);
}
}
private static void denseRanking(int len, int[][] groups) {
System.out.println("\nDense ranking");
for (int i = 0, rank = 0; i < len; i++) {
if (rank < groups.length && i == groups[rank][0])
rank++;
System.out.printf("%d %s%n", rank, input[i]);
}
}
private static void ordinalRanking(int len) {
System.out.println("\nOrdinal ranking");
for (int i = 0; i < len; i++)
System.out.printf("%d %s%n", i + 1, input[i]);
}
private static void fractionalRanking(int len, int[][] groups) {
System.out.println("\nFractional ranking");
float rank = 0;
for (int i = 0, tmp = 0, group = 0; i < len; i++) {
if (group < groups.length && i == groups[group][0]) {
tmp += groups[group++][1];
rank = (i + 1 + tmp) / 2.0F;
}
System.out.printf("%2.1f %s%n", rank, input[i]);
}
}
}

View file

@ -0,0 +1,45 @@
my @scores =
Solomon => 44,
Jason => 42,
Errol => 42,
Garry => 41,
Bernard => 41,
Barry => 41,
Stephen => 39;
sub tiers (@s) { @s.classify(*.value).pairs.sort.reverse.map: { [.value».key] } }
sub standard (@s) {
my $rank = 1;
gather for tiers @s -> @players {
take $rank => @players;
$rank += @players;
}
}
sub modified (@s) {
my $rank = 0;
gather for tiers @s -> @players {
$rank += @players;
take $rank => @players;
}
}
sub dense (@s) { tiers(@s).map: { ++$_ => @^players } }
sub ordinal (@s) { @s.map: ++$_ => *.key }
sub fractional (@s) {
my $rank = 1;
gather for tiers @s -> @players {
my $beg = $rank;
my $end = $rank += @players;
take [+]($beg ..^ $end) / @players => @players;
}
}
say "Standard:"; .say for standard @scores;
say "\nModified:"; .say for modified @scores;
say "\nDense:"; .say for dense @scores;
say "\nOrdinal:"; .say for ordinal @scores;
say "\nFractional:"; .say for fractional @scores;

View file

@ -0,0 +1,74 @@
def mc_rank(iterable, start=1):
"""Modified competition ranking"""
lastresult, fifo = None, []
for n, item in enumerate(iterable, start-1):
if item[0] == lastresult:
fifo += [item]
else:
while fifo:
yield n, fifo.pop(0)
lastresult, fifo = item[0], fifo + [item]
while fifo:
yield n+1, fifo.pop(0)
def sc_rank(iterable, start=1):
"""Standard competition ranking"""
lastresult, lastrank = None, None
for n, item in enumerate(iterable, start):
if item[0] == lastresult:
yield lastrank, item
else:
yield n, item
lastresult, lastrank = item[0], n
def d_rank(iterable, start=1):
"""Dense ranking"""
lastresult, lastrank = None, start - 1,
for item in iterable:
if item[0] == lastresult:
yield lastrank, item
else:
lastresult, lastrank = item[0], lastrank + 1
yield lastrank, item
def o_rank(iterable, start=1):
"""Ordinal ranking"""
yield from enumerate(iterable, start)
def f_rank(iterable, start=1):
"""Fractional ranking"""
last, fifo = None, []
for n, item in enumerate(iterable, start):
if item[0] != last:
if fifo:
mean = sum(f[0] for f in fifo) / len(fifo)
while fifo:
yield mean, fifo.pop(0)[1]
last = item[0]
fifo.append((n, item))
if fifo:
mean = sum(f[0] for f in fifo) / len(fifo)
while fifo:
yield mean, fifo.pop(0)[1]
if __name__ == '__main__':
scores = [(44, 'Solomon'),
(42, 'Jason'),
(42, 'Errol'),
(41, 'Garry'),
(41, 'Bernard'),
(41, 'Barry'),
(39, 'Stephen')]
print('\nScores to be ranked (best first):')
for s in scores:
print(' %2i %s' % (s ))
for ranker in [sc_rank, mc_rank, d_rank, o_rank, f_rank]:
print('\n%s:' % ranker.__doc__)
for rank, score in ranker(scores):
print(' %3g, %r' % (rank, score))

View file

@ -0,0 +1 @@
Data source: http://rosettacode.org/wiki/Ranking_methods

View file

@ -0,0 +1,77 @@
#lang racket
;; Tim-brown 2014-09-11
;; produces a ranking according to ranking function: rfn
;; INPUT:
;; lst : (list (score . details))
;; rfn : (length-scores)
;; -> (values
;; ranks-added ; how many ranks to add for the next iteration
;; (idx . rest -> rank-offset)) ; function that produces the rank for the idx^th element
;; ; in the scoring (arity must be >= 1)
(define (rank-list all-scores rfn)
(let loop ((rank-0 0) (lst (sort all-scores > #:key car)) (acc empty))
(cond
[(null? lst) acc]
[else
(define 1st-score (caar lst))
(define (ties-with-1st? cand) (= (car cand) 1st-score))
(define-values (tied unranked) (splitf-at lst ties-with-1st?))
;; all ranking functions should properly handle a singleton tied list
(define tied-len (length tied))
(define tied? (> tied-len 1))
(define-values (ranks-added rank-offset-fn) (rfn tied-len))
(define ranked-tied (for/list ((t (in-list tied)) (i (in-naturals 1)))
(list* tied? (+ rank-0 (rank-offset-fn i)) t)))
(loop (+ ranks-added rank-0) unranked (append acc ranked-tied))])))
;; Ties share what would have been their first ordinal number
(define (rank-function:Standard l)
(values l (thunk* 1)))
;; Ties share what would have been their last ordinal number
(define (rank-function:Modified l)
(values l (thunk* l)))
;; Ties share the next available integer
(define (rank-function:Dense l)
(values 1 (thunk* 1)))
;; Competitors take the next available integer. Ties are not treated otherwise
(define (rank-function:Ordinal l)
(values l (λ (n . _) n)))
;; Ties share the mean of what would have been their ordinal numbers
(define (rank-function:Fractional l)
(values l (thunk* (/ (+ l 1) 2))))
(define score-board
'((44 . Solomon)
(42 . Jason)
(42 . Errol)
(41 . Garry)
(41 . Bernard)
(41 . Barry)
(39 . Stephen)))
(define format-number
(match-lambda
[(? integer? i) i]
[(and f (app numerator n) (app denominator d))
(define-values (q r) (quotient/remainder n d))
(format "~a ~a/~a" q r d)]))
(for ((fn (list
rank-function:Standard
rank-function:Modified
rank-function:Dense
rank-function:Ordinal
rank-function:Fractional)))
(printf "Function: ~s~%" fn)
(for ((r (in-list (rank-list score-board fn))))
(printf "~a ~a\t~a\t~a~%"
(if (car r) "=" " ")
(format-number (cadr r))
(caddr r)
(cdddr r)))
(newline))

View file

@ -0,0 +1,23 @@
ar = "44 Solomon
42 Jason
42 Errol
41 Garry
41 Bernard
41 Barry
39 Stephen".lines.map{|line| line.split}
grouped = ar.group_by{|pair| pair.delete_at(0).to_i}
s_rnk = 1
m_rnk = o_rnk = f_rnk = 0
puts "stand.\tmod.\tdense\tord.\tfract."
grouped.each.with_index do |(score, names), i|
d_rnk = i + 1
m_rnk += names.flatten!.size
f_rnk = (s_rnk + m_rnk)/2.0
names.each do |name|
o_rnk += 1
puts "#{s_rnk}\t#{m_rnk}\t#{d_rnk}\t#{o_rnk}\t#{f_rnk.to_s.gsub(".0","")}\t#{score} #{name}"
end
s_rnk += names.size
end

View file

@ -0,0 +1,44 @@
object RankingMethods extends App {
case class Score(score: Int, name: String) // incoming data
case class Rank[Precision](rank: Precision, names: List[String]) // outgoing results (can be int or double)
case class State[Precision](n: Int, done: List[Rank[Precision]]) { // internal state, no mutable variables
def next(n: Int, next: Rank[Precision]) = State(n, next :: done)
}
def grouped[Precision](list: List[Score]) = // group names together by score, with highest first
(scala.collection.immutable.TreeMap[Int, List[Score]]() ++ list.groupBy(-_.score))
.values.map(_.map(_.name)).foldLeft(State[Precision](1, Nil)) _
// Ranking methods:
def rankStandard(list: List[Score]) =
grouped[Int](list){case (state, names) => state.next(state.n+names.length, Rank(state.n, names))}.done.reverse
def rankModified(list: List[Score]) =
rankStandard(list).map(r => Rank(r.rank+r.names.length-1, r.names))
def rankDense(list: List[Score]) =
grouped[Int](list){case (state, names) => state.next(state.n+1, Rank(state.n, names))}.done.reverse
def rankOrdinal(list: List[Score]) =
list.zipWithIndex.map{case (score, n) => Rank(n+1, List(score.name))}
def rankFractional(list: List[Score]) =
rankStandard(list).map(r => Rank((2*r.rank+r.names.length-1.0)/2, r.names))
// Tests:
def parseScores(s: String) = s split "\\s+" match {case Array(s,n) => Score(s.toInt, n)}
val test = List("44 Solomon", "42 Jason", "42 Errol", "41 Garry", "41 Bernard", "41 Barry", "39 Stephen").map(parseScores)
println("Standard:")
println(rankStandard(test) mkString "\n")
println("\nModified:")
println(rankModified(test) mkString "\n")
println("\nDense:")
println(rankDense(test) mkString "\n")
println("\nOrdinal:")
println(rankOrdinal(test) mkString "\n")
println("\nFractional:")
println(rankFractional(test) mkString "\n")
}

View file

@ -0,0 +1,56 @@
proc rank {rankingMethod sortedList} {
# Extract the groups in the data (this is pointless for ordinal...)
set s [set group [set groups {}]]
foreach {score who} $sortedList {
if {$score != $s} {
lappend groups [llength $group]
set s $score
set group {}
}
lappend group $who
}
lappend groups [llength $group]
# Construct the rankings; note that we have a zero-sized leading group
set n 1; set m 0
foreach g $groups {
switch $rankingMethod {
standard {
lappend result {*}[lrepeat $g $n]
incr n $g
}
modified {
lappend result {*}[lrepeat $g [incr m $g]]
}
dense {
lappend result {*}[lrepeat $g $m]
incr m
}
ordinal {
for {set i 0} {$i < $g} {incr i} {
lappend result [incr m]
}
}
fractional {
set val [expr {($n + [incr n $g] - 1) / 2.0}]
lappend result {*}[lrepeat $g [format %g $val]]
}
}
}
return $result
}
set data {
44 Solomon
42 Jason
42 Errol
41 Garry
41 Bernard
41 Barry
39 Stephen
}
foreach method {standard modified dense ordinal fractional} {
puts "Using method '$method'...\n Rank\tScore\tWho"
foreach rank [rank $method $data] {score who} $data {
puts " $rank\t$score\t$who"
}
}