with Ada.Text_IO;
with Ada.Containers.Vectors;

procedure Range_Consolidation is

   type Set_Type is record
      Left, Right : Float;
   end record;

   package Set_Vectors is
      new Ada.Containers.Vectors (Positive, Set_Type);

   procedure Normalize (Set : in out Set_Vectors.Vector) is

      function Less_Than (Left, Right : Set_Type) return Boolean is
         begin Return Left.Left < Right.Left; end;

      package Set_Sorting is
         new Set_Vectors.Generic_Sorting (Less_Than);
   begin
      for Elem of Set loop
         Elem := (Left  => Float'Min (Elem.Left,  Elem.Right),
                  Right => Float'Max (Elem.Left,  Elem.Right));
      end loop;
      Set_Sorting.Sort (Set);
   end Normalize;

   procedure Consolidate (Set : in out Set_Vectors.Vector) is
      use Set_Vectors;
      First : Cursor := Set.First;
      Last  : Cursor := Next (First);
   begin
      while Last /= No_Element loop
         if Element (First).Right < Element (Last).Left then      -- non-overlap
            First := Last;
            Last  := Next (Last);
         elsif Element (First).Right >= Element (Last).Left then  -- overlap
            Replace_Element (Set, First, (Left  => Element (First).Left,
                                          Right => Float'Max (Element (First).Right,
                                                              Element (Last) .Right)));
            Delete (Set, Last);
            Last := Next (First);
         end if;
      end loop;
   end Consolidate;

   procedure Put (Set : in Set_Vectors.Vector) is
      package Float_IO is
         new Ada.Text_IO.Float_IO (Float);
   begin
      Float_IO.Default_Exp  := 0;
      Float_IO.Default_Aft  := 1;
      Float_IO.Default_Fore := 3;
      for Elem of Set loop
         Ada.Text_IO.Put ("(");
         Float_IO.Put (Elem.Left);
         Float_IO.Put (Elem.Right);
         Ada.Text_IO.Put (") ");
      end loop;
   end Put;

   procedure Show (Set : in out Set_Vectors.Vector) is
      use Ada.Text_IO;
   begin
      Put (Set);
      Normalize (Set);
      Consolidate (Set);
      Set_Col (70);
      Put (Set);
      New_Line;
   end Show;

   use Set_Vectors;
   Set_0 : Set_Vectors.Vector := Empty_Vector;
   Set_1 : Set_Vectors.Vector := Empty_Vector & (1.1, 2.2);
   Set_2 : Set_Vectors.Vector := (6.1, 7.2) & (7.2, 8.3);
   Set_3 : Set_Vectors.Vector := (4.0, 3.0) & (2.0, 1.0);
   Set_4 : Set_Vectors.Vector := (4.0, 3.0) & (2.0, 1.0) & (-1.0, -2.0) & (3.9, 10.0);
   Set_5 : Set_Vectors.Vector := (1.0, 3.0) & (-6.0, -1.0) & (-4.0, -5.0) & (8.0, 2.0) & (-6.0, -6.0);
begin
   Show (Set_0);
   Show (Set_1);
   Show (Set_2);
   Show (Set_3);
   Show (Set_4);
   Show (Set_5);
end Range_Consolidation;


RangeConsolidation(arr){
	arr1 := [],	arr2 := [], result := []

	for i, obj in arr
		arr1[i,1] := min(arr[i]*), arr1[i,2] := max(arr[i]*)	; sort each range individually

	for i, obj in arr1
		if (obj.2 > arr2[obj.1])
			arr2[obj.1] := obj.2				; creates helper array sorted by range

	i := 1
	for start, stop in arr2
		if (i = 1) || (start > result[i-1, 2])			; first or non overlapping range
			result[i, 1] := start, result[i, 2] := stop, i++
		else							; overlapping range
			result[i-1, 2] := stop > result[i-1, 2] ? stop : result[i-1, 2]
	return result
}


#include <stdio.h>
#include <stdlib.h>

typedef struct range_tag {
    double low;
    double high;
} range_t;

void normalize_range(range_t* range) {
    if (range->high < range->low) {
        double tmp = range->low;
        range->low = range->high;
        range->high = tmp;
    }
}

int range_compare(const void* p1, const void* p2) {
    const range_t* r1 = p1;
    const range_t* r2 = p2;
    if (r1->low < r2->low)
        return -1;
    if (r1->low > r2->low)
        return 1;
    if (r1->high < r2->high)
        return -1;
    if (r1->high > r2->high)
        return 1;
    return 0;
}

void normalize_ranges(range_t* ranges, size_t count) {
    for (size_t i = 0; i < count; ++i)
        normalize_range(&ranges[i]);
    qsort(ranges, count, sizeof(range_t), range_compare);
}

// Consolidates an array of ranges in-place. Returns the
// number of ranges after consolidation.
size_t consolidate_ranges(range_t* ranges, size_t count) {
    normalize_ranges(ranges, count);
    size_t out_index = 0;
    for (size_t i = 0; i < count; ) {
        size_t j = i;
        while (++j < count && ranges[j].low <= ranges[i].high) {
            if (ranges[i].high < ranges[j].high)
                ranges[i].high = ranges[j].high;
        }
        ranges[out_index++] = ranges[i];
        i = j;
    }
    return out_index;
}

void print_range(const range_t* range) {
    printf("[%g, %g]", range->low, range->high);
}

void print_ranges(const range_t* ranges, size_t count) {
    if (count == 0)
        return;
    print_range(&ranges[0]);
    for (size_t i = 1; i < count; ++i) {
        printf(", ");
        print_range(&ranges[i]);
    }
}

void test_consolidate_ranges(range_t* ranges, size_t count) {
    print_ranges(ranges, count);
    printf(" -> ");
    count = consolidate_ranges(ranges, count);
    print_ranges(ranges, count);
    printf("\n");
}

#define LENGTHOF(a) sizeof(a)/sizeof(a[0])

int main() {
    range_t test1[] = { {1.1, 2.2} };
    range_t test2[] = { {6.1, 7.2}, {7.2, 8.3} };
    range_t test3[] = { {4, 3}, {2, 1} };
    range_t test4[] = { {4, 3}, {2, 1}, {-1, -2}, {3.9, 10} };
    range_t test5[] = { {1, 3}, {-6, -1}, {-4, -5}, {8, 2}, {-6, -6} };
    test_consolidate_ranges(test1, LENGTHOF(test1));
    test_consolidate_ranges(test2, LENGTHOF(test2));
    test_consolidate_ranges(test3, LENGTHOF(test3));
    test_consolidate_ranges(test4, LENGTHOF(test4));
    test_consolidate_ranges(test5, LENGTHOF(test5));
    return 0;
}


using static System.Math;
using System.Linq;
using System;

public static class RangeConsolidation
{
    public static void Main() {
        foreach (var list in new [] {
            new[] { (1.1, 2.2) }.ToList(),
            new[] { (6.1, 7.2), (7.2, 8.3) }.ToList(),
            new[] { (4d, 3d), (2, 1) }.ToList(),
            new[] { (4d, 3d), (2, 1), (-1, 2), (3.9, 10) }.ToList(),
            new[] { (1d, 3d), (-6, -1), (-4, -5), (8, 2), (-6, -6) }.ToList()
        })
        {
            for (int z = list.Count-1; z >= 1; z--) {
                for (int y = z - 1; y >= 0; y--) {
                    if (Overlap(list[z], list[y])) {
                        list[y] = Consolidate(list[z], list[y]);
                        list.RemoveAt(z);
                        break;
                    }
                }
            }
            Console.WriteLine(string.Join(", ", list.Select(Normalize).OrderBy(range => range.s)));
        }
    }

    private static bool Overlap((double s, double e) left, (double s, double e) right) =>
        Max(left.s, left.e) > Max(right.s, right.e)
        ? Max(right.s, right.e) >= Min(left.s, left.e)
        : Max(left.s, left.e) >= Min(right.s, right.e);

    private static (double s, double e) Consolidate((double s, double e) left, (double s, double e) right) =>
        (Min(Min(left.s, left.e), Min(right.s, right.e)), Max(Max(left.s, left.e), Max(right.s, right.e)));

    private static (double s, double e) Normalize((double s, double e) range) =>
        (Min(range.s, range.e), Max(range.s, range.e));
}


#include <algorithm>
#include <iostream>
#include <utility>
#include <vector>

// A range is represented as std::pair<from, to>

template <typename iterator>
void normalize_ranges(iterator begin, iterator end) {
    for (iterator i = begin; i != end; ++i) {
        if (i->second < i->first)
            std::swap(i->first, i->second);
    }
    std::sort(begin, end);
}

// Merges a range of ranges in-place. Returns an iterator to the
// end of the resulting range, similarly to std::remove.
template <typename iterator>
iterator merge_ranges(iterator begin, iterator end) {
    iterator out = begin;
    for (iterator i = begin; i != end; ) {
        iterator j = i;
        while (++j != end && j->first <= i->second)
            i->second = std::max(i->second, j->second);
        *out++ = *i;
        i = j;
    }
    return out;
}

template <typename iterator>
iterator consolidate_ranges(iterator begin, iterator end) {
    normalize_ranges(begin, end);
    return merge_ranges(begin, end);
}

template <typename pair>
void print_range(std::ostream& out, const pair& range) {
    out << '[' << range.first << ", " << range.second << ']';
}

template <typename iterator>
void print_ranges(std::ostream& out, iterator begin, iterator end) {
    if (begin != end) {
        print_range(out, *begin++);
        for (; begin != end; ++begin) {
            out << ", ";
            print_range(out, *begin);
        }
    }
}

int main() {
    std::vector<std::pair<double, double>> test_cases[] = {
        { {1.1, 2.2} },
        { {6.1, 7.2}, {7.2, 8.3} },
        { {4, 3}, {2, 1} },
        { {4, 3}, {2, 1}, {-1, -2}, {3.9, 10} },
        { {1, 3}, {-6, -1}, {-4, -5}, {8, 2}, {-6, -6} }
    };
    for (auto&& ranges : test_cases) {
        print_ranges(std::cout, std::begin(ranges), std::end(ranges));
        std::cout << " -> ";
        auto i = consolidate_ranges(std::begin(ranges), std::end(ranges));
        print_ranges(std::cout, std::begin(ranges), i);
        std::cout << '\n';
    }
    return 0;
}


(defn normalize [r]
  (let [[n1 n2] r]
    [(min n1 n2) (max n1 n2)]))

(defn touch? [r1 r2]
  (let [[lo1 hi1] (normalize r1)
        [lo2 hi2] (normalize r2)]
    (or (<= lo2 lo1 hi2)
        (<= lo2 hi1 hi2))))

(defn consolidate-touching-ranges [rs]
  (let [lows  (map #(apply min %) rs)
        highs (map #(apply max %) rs)]
    [ (apply min lows) (apply max highs) ]))

(defn consolidate-ranges [rs]
  (loop [res []
         rs  rs]
    (if (empty? rs)
      res
      (let [r0 (first rs)
            touching (filter #(touch? r0 %) rs)
            remove-used (fn [rs used]
                          (remove #(contains? (set used) %) rs))]
        (recur (conj res (consolidate-touching-ranges touching))
               (remove-used (rest rs) touching))))))


type Pt(s, e) with Lookup

func Pt.Min() => min(this.s, this.e)
func Pt.Max() => max(this.s, this.e)
func Pt.ToString() => "(\(this.s), \(this.e))"

let rng = [
    [ Pt(1.1, 2.2) ],
    [ Pt(6.1, 7.2), Pt(7.2, 8.3) ],
    [ Pt(4.0, 3.0), Pt(2, 1) ],
    [ Pt(4.0, 3.0), Pt(2, 1),  Pt(-1, 2),  Pt(3.9, 10) ],
    [ Pt(1.0, 3.0), Pt(-6, -1), Pt(-4, -5), Pt(8,   2), Pt(-6, -6) ]
]

func overlap(left, right) =>
    left.Max() > right.Max() ? right.Max() >= left.Min()
    : left.Max() >= right.Min()

func consolidate(left, right) => Pt(min(left.Min(), right.Min()), max(left.Max(), right.Max()))

func normalize(range) => Pt(range.Min(), range.Max())

for list in rng {
    var z = list.Length() - 1

    while z >= 1 {
        for y in (z - 1)^-1..0 when overlap(list[z], list[y]) {
            list[y] = consolidate(list[z], list[y])
            break list.RemoveAt(z)
        }
        z -= 1
    }

    for i in list.Indices() {
        list[i] = normalize(list[i])
    }

    list.Sort((x,y) => x.s - y.s)
    print(list)
}


USING: arrays combinators formatting kernel math.combinatorics
math.order math.statistics sequences sets sorting ;

: overlaps? ( pair pair -- ? )
    2dup swap [ [ first2 between? ] curry any? ] [email protected] or ;

: merge ( seq -- newseq ) concat minmax 2array 1array ;

: merge1 ( seq -- newseq )
    dup 2 [ first2 overlaps? ] find-combination
    [ [ without ] keep merge append ] when* ;

: normalize ( seq -- newseq ) [ natural-sort ] map ;

: consolidate ( seq -- newseq )
    normalize [ merge1 ] to-fixed-point natural-sort ;

{
    { { 1.1 2.2 } }
    { { 6.1 7.2 } { 7.2 8.3 } }
    { { 4 3 } { 2 1 } }
    { { 4 3 } { 2 1 } { -1 -2 } { 3.9 10 } }
    { { 1 3 } { -6 -1 } { -4 -5 } { 8 2 } { -6 -6 } }
} [ dup consolidate "%49u => %u\n" printf ] each


Dim Shared As Integer i
Dim Shared As Single items, temp = 10^30

Sub ordenar(tabla() As Single)
    Dim As Integer t1, t2
    Dim As Boolean s

    Do
        s = True
        For i = 1 To Ubound(tabla)-1
            If tabla(i, 1) > tabla(i+1, 1) Then
                t1 = tabla(i, 1) : t2 = tabla(i, 2)
                tabla(i, 1) = tabla(i + 1, 1) : tabla(i, 2) = tabla(i + 1, 2)
                tabla(i + 1, 1) = t1 : tabla(i + 1, 2) = t2
                s = False
            End If
        Next i
    Loop Until(s)
End Sub

Sub normalizar(tabla() As Single)
    Dim As Integer t

    For i = 1 To Ubound(tabla)
        If tabla(i, 1) > tabla(i, 2) Then
            t = tabla(i, 1)
            tabla(i, 1) = tabla(i, 2)
            tabla(i, 2) = t
        End If
    Next i

    ordenar(tabla())
End Sub

Sub consolidar(tabla() As Single)

    normalizar(tabla())

    For i = 1 To Ubound(tabla)-1
        If tabla(i + 1, 1) <= tabla(i, 2) Then
            tabla(i + 1, 1) = tabla(i, 1)
            If tabla(i + 1, 2) <= tabla(i, 2) Then
                tabla(i + 1, 2) = tabla(i, 2)
            End If
            tabla(i, 1) = temp : tabla(i, 2) = temp
        End If
    Next i
End Sub

Data 1, 1.1, 2.2
Data 2, 6.1, 7.2, 7.2, 8.3
Data 2, 4, 3, 2, 1
Data 4, 4, 3, 2, 1, -1, -2, 3.9, 10
Data 5, 1,3, -6,-1, -4,-5, 8,2, -6,-6

For j As Byte = 1 To 5
    Read items

    Dim As Single tabla(items,  2)
    For i = 1 To items
        Read tabla(i, 1), tabla(i, 2)
    Next i

    consolidar(tabla())

    For i = 1 To items
        If tabla(i, 1) <> temp Then Print "[";tabla(i, 1); ", "; tabla(i, 2); "] ";
    Next i
    Print
Next j
Sleep


package main

import (
    "fmt"
    "math"
    "sort"
)

type Range struct{ Lower, Upper float64 }

func (r Range) Norm() Range {
    if r.Lower > r.Upper {
        return Range{r.Upper, r.Lower}
    }
    return r
}

func (r Range) String() string {
    return fmt.Sprintf("[%g, %g]", r.Lower, r.Upper)
}

func (r1 Range) Union(r2 Range) []Range {
    if r1.Upper < r2.Lower {
        return []Range{r1, r2}
    }
    r := Range{r1.Lower, math.Max(r1.Upper, r2.Upper)}
    return []Range{r}
}

func consolidate(rs []Range) []Range {
    for i := range rs {
        rs[i] = rs[i].Norm()
    }
    le := len(rs)
    if le < 2 {
        return rs
    }
    sort.Slice(rs, func(i, j int) bool {
        return rs[i].Lower < rs[j].Lower
    })
    if le == 2 {
        return rs[0].Union(rs[1])
    }
    for i := 0; i < le-1; i++ {
        for j := i + 1; j < le; j++ {
            ru := rs[i].Union(rs[j])
            if len(ru) == 1 {
                rs[i] = ru[0]
                copy(rs[j:], rs[j+1:])
                rs = rs[:le-1]
                le--
                i--
                break
            }
        }
    }
    return rs
}

func main() {
    rss := [][]Range{
        {{1.1, 2.2}},
        {{6.1, 7.2}, {7.2, 8.3}},
        {{4, 3}, {2, 1}},
        {{4, 3}, {2, 1}, {-1, -2}, {3.9, 10}},
        {{1, 3}, {-6, -1}, {-4, -5}, {8, 2}, {-6, -6}},
    }
    for _, rs := range rss {
        s := fmt.Sprintf("%v", rs)
        fmt.Printf("%40s => ", s[1:len(s)-1])
        rs2 := consolidate(rs)
        s = fmt.Sprintf("%v", rs2)
        fmt.Println(s[1 : len(s)-1])
    }
}


import Data.List (intercalate, maximumBy, sort)
import Data.Ord (comparing)

------------------- RANGE CONSOLIDATION ------------------

consolidated :: [(Float, Float)] -> [(Float, Float)]
consolidated = foldr go [] . sort . fmap ab
  where
    go xy [] = [xy]
    go xy@(x, y) abetc@((a, b) : etc)
      | y >= b = xy : etc
      | y >= a = (x, b) : etc
      | otherwise = xy : abetc
    ab (a, b)
      | a <= b = (a, b)
      | otherwise = (b, a)

--------------------------- TEST -------------------------
tests :: [[(Float, Float)]]
tests =
  [ [],
    [(1.1, 2.2)],
    [(6.1, 7.2), (7.2, 8.3)],
    [(4, 3), (2, 1)],
    [(4, 3), (2, 1), (-1, -2), (3.9, 10)],
    [(1, 3), (-6, -1), (-4, -5), (8, 2), (-6, -6)]
  ]

main :: IO ()
main =
  putStrLn $
    tabulated
      "Range consolidations:"
      showPairs
      showPairs
      consolidated
      tests

-------------------- DISPLAY FORMATTING ------------------

tabulated ::
  String ->
  (a -> String) ->
  (b -> String) ->
  (a -> b) ->
  [a] ->
  String
tabulated s xShow fxShow f xs =
  let w =
        length $
          maximumBy
            (comparing length)
            (xShow <$> xs)
      rjust n c s = drop (length s) (replicate n c <> s)
   in unlines $
        s :
        fmap
          ( ((<>) . rjust w ' ' . xShow)
              <*> ((" -> " <>) . fxShow . f)
          )
          xs

showPairs :: [(Float, Float)] -> String
showPairs xs
  | null xs = "[]"
  | otherwise =
    '[' :
    intercalate
      ", "
      (showPair <$> xs)
      <> "]"

showPair :: (Float, Float) -> String
showPair (a, b) =
  '(' :
  showNum a
    <> ", "
    <> showNum b
    <> ")"

showNum :: Float -> String
showNum n
  | 0 == (n - fromIntegral (round n)) = show (round n)
  | otherwise = show n


ensure2D=: ,:^:(1 = #@$)                 NB. if list make 1 row table
normalise=: ([: /:~ /:~"1)@ensure2D      NB. normalises list of ranges
merge=: ,:`(<.&{. , >.&{:)@.(>:/&{: |.)  NB. merge ranges x and y
consolidate=: (}[email protected]] ,~ (merge {.)) ensure2D


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class RangeConsolidation {

    public static void main(String[] args) {
        displayRanges( Arrays.asList(new Range(1.1, 2.2)));
        displayRanges( Arrays.asList(new Range(6.1, 7.2), new Range(7.2, 8.3)));
        displayRanges( Arrays.asList(new Range(4, 3), new Range(2, 1)));
        displayRanges( Arrays.asList(new Range(4, 3), new Range(2, 1), new Range(-1, -2), new Range(3.9, 10)));
        displayRanges( Arrays.asList(new Range(1, 3), new Range(-6, -1), new Range(-4, -5), new Range(8, 2), new Range(-6, -6)));
        displayRanges( Arrays.asList(new Range(1, 1), new Range(1, 1)));
        displayRanges( Arrays.asList(new Range(1, 1), new Range(1, 2)));
        displayRanges( Arrays.asList(new Range(1, 2), new Range(3, 4), new Range(1.5, 3.5), new Range(1.2, 2.5)));
    }

    private static final void displayRanges(List<Range> ranges) {
        System.out.printf("ranges = %-70s, colsolidated = %s%n", ranges, Range.consolidate(ranges));
    }

    private static final class RangeSorter implements Comparator<Range> {
        @Override
        public int compare(Range o1, Range o2) {
            return (int) (o1.left - o2.left);
        }
    }

    private static class Range {
        double left;
        double right;

        public Range(double left, double right) {
            if ( left <= right ) {
                this.left = left;
                this.right = right;
            }
            else {
                this.left = right;
                this.right = left;
            }
        }

        public Range consolidate(Range range) {
            //  no overlap
            if ( this.right < range.left ) {
                return null;
            }
            //  no overlap
            if ( range.right < this.left ) {
                return null;
            }
            //  contained
            if ( this.left <= range.left && this.right >= range.right ) {
                return this;
            }
            //  contained
            if ( range.left <= this.left && range.right >= this.right ) {
                return range;
            }
            //  overlap
            if ( this.left <= range.left && this.right <= range.right ) {
                return new Range(this.left, range.right);
            }
            //  overlap
            if ( this.left >= range.left && this.right >= range.right ) {
                return new Range(range.left, this.right);
            }
            throw new RuntimeException("ERROR:  Logic invalid.");
        }

        @Override
        public String toString() {
            return "[" + left + ", " + right + "]";
        }

        private static List<Range> consolidate(List<Range> ranges) {
            List<Range> consolidated = new ArrayList<>();

            Collections.sort(ranges, new RangeSorter());

            for ( Range inRange : ranges ) {
                Range r = null;
                Range conRange = null;
                for ( Range conRangeLoop : consolidated ) {
                    r = inRange.consolidate(conRangeLoop);
                    if (r != null ) {
                        conRange = conRangeLoop;
                        break;
                    }
                }
                if ( r == null ) {
                    consolidated.add(inRange);
                }
                else {
                    consolidated.remove(conRange);
                    consolidated.add(r);
                }
            }

            Collections.sort(consolidated, new RangeSorter());

            return consolidated;
        }
    }

}


normalize(s) = sort([sort(bounds) for bounds in s])

function consolidate(ranges)
    norm = normalize(ranges)
    for (i, r1) in enumerate(norm)
        if !isempty(r1)
            for r2 in norm[i+1:end]
                if !isempty(r2) && r1[end] >= r2[1]     # intersect?
                    r1 .= [r1[1], max(r1[end], r2[end])]
                    empty!(r2)
                end
            end
        end
    end
    [r for r in norm if !isempty(r)]
end

function testranges()
    for s in [[[1.1, 2.2]], [[6.1, 7.2], [7.2, 8.3]], [[4, 3], [2, 1]],
              [[4, 3], [2, 1], [-1, -2], [3.9, 10]],
              [[1, 3], [-6, -1], [-4, -5], [8, 2], [-6, -6]]]
        println("$s => $(consolidate(s))")
    end
end

testranges()


fun <T> consolidate(ranges: Iterable<ClosedRange<T>>): List<ClosedRange<T>> where T : Comparable<T>
{
    return ranges
        .sortedWith(compareBy({ it.start }, { it.endInclusive }))
        .asReversed()
        .fold(mutableListOf<ClosedRange<T>>()) {
            consolidatedRanges, range ->
            if (consolidatedRanges.isEmpty())
            {
                consolidatedRanges.add(range)
            }
            // Keep in mind the reverse-sorting applied above:
            // If the end of the current-range is higher, than it must start at a lower value,
            else if (range.endInclusive >= consolidatedRanges[0].endInclusive)
            {
                consolidatedRanges[0] = range
            }
            else if (range.endInclusive >= consolidatedRanges[0].start)
            {
                consolidatedRanges[0] = range.start .. consolidatedRanges[0].endInclusive
            }
            else
            {
                consolidatedRanges.add(0, range)
            }

            [email protected] consolidatedRanges
        }
        .toList()
}

// What a bummer! Kotlin's range syntax (a..b) doesn't meet the task requirements when b < b,
// and on the other hand, the syntax for constructing lists, arrays and pairs isn't close enough
// to the range notation. Instead then, here's a *very* naive parser. Don't take it seriously.
val rangeRegex = Regex("""\[(.+),(.+)\]""")
fun parseDoubleRange(rangeStr: String): ClosedFloatingPointRange<Double> {
    val parts = rangeRegex
        .matchEntire(rangeStr)
        ?.groupValues
        ?.drop(1)
        ?.map { it.toDouble() }
        ?.sorted()
    if (parts == null) throw IllegalArgumentException("Unable to parse range $rangeStr")
    return parts[0] .. parts[1]
}

fun serializeRange(range: ClosedRange<*>) = "[${range.start}, ${range.endInclusive}]"

// See above. In practice you'd probably use consolidate directly
fun consolidateDoubleRanges(rangeStrings: Iterable<String>): List<String>
{
    return consolidate(rangeStrings.asSequence().map(::parseDoubleRange).toList()).map(::serializeRange)
}

fun main() {
    val inputRanges = listOf(
        listOf("[1.1, 2.2]"),
        listOf("[6.1, 7.2]", "[7.2, 8.3]"),
        listOf("[4, 3]", "[2, 1]"),
        listOf("[4, 3]", "[2, 1]", "[-1, -2]", "[3.9, 10]"),
        listOf("[1, 3]", "[-6, -1]", "[-4, -5]", "[8, 2]", "[-6, -6]")
    )

    inputRanges.associateBy(Any::toString, ::consolidateDoubleRanges).forEach({ println("${it.key} => ${it.value}") })
}


import algorithm, strutils

# Definition of a range of values of type T.
type Range[T] = array[2, T]

proc `<`(a, b: Range): bool {.inline.} =
  ## Check if range "a" is less than range "b". Needed for sorting.
  if a[0] == b[0]:
    a[1] < b[1]
  else:
    a[0] < b[0]

proc consolidate[T](rangeList: varargs[Range[T]]): seq[Range[T]] =
  ## Consolidate a list of ranges of type T.

  # Build a sorted list of normalized ranges.
  var list: seq[Range[T]]
  for item in rangeList:
    list.add if item[0] <= item[1]: item else: [item[1], item[0]]
  list.sort()

  # Build the consolidated list starting from "smallest" range.
  result.add list[0]
  for i in 1..list.high:
    let rangeMin = result[^1]
    let rangeMax = list[i]
    if rangeMax[0] <= rangeMin[1]:
      result[^1] = [rangeMin[0], max(rangeMin[1], rangeMax[1])]
    else:
      result.add rangeMax

proc `$`[T](r: Range[T]): string {.inline.} =
  # Return the string representation of a range.
  when T is SomeFloat:
    "[$1, $2]".format(r[0].formatFloat(ffDecimal, 1), r[1].formatFloat(ffDecimal, 1))
  else:
    "[$1, $2]".format(r[0], r[1])

proc `$`[T](s: seq[Range[T]]): string {.inline.} =
  ## Return the string representation of a sequence of ranges.
  s.join(", ")

when isMainModule:

  proc test[T](rangeList: varargs[Range[T]]) =
    echo ($(@rangeList)).alignLeft(52), "→   ", consolidate(rangeList)

  test([1.1, 2.2])
  test([6.1, 7.2], [7.2, 8.3])
  test([4, 3], [2, 1])
  test([4.0, 3.0], [2.0, 1.0], [-1.0, -2.0], [3.9, 10.0])
  test([1, 3], [-6, -1], [-4, -5], [8, 2], [-6, -6])


with javascript_semantics
function consolidate(sequence sets)
    integer l = length(sets)
    sequence res = repeat(0,l)
    for i=1 to l do
        atom {rs,re} = sets[i]
        res[i] = iff(rs>re?{re,rs}:{rs,re})
    end for
    for i=l to 1 by -1 do
        atom {il,ih} = res[i]
        for j=l to i+1 by -1 do
            atom {jl,jh} = res[j]
            bool overlap = iff(il<=jl?jl<=ih:il<=jh)
            if overlap then
                {il,ih} = {min(il,jl),max(ih,jh)}
                res[j] = res[l]
                l -= 1
            end if
        end for
        res[i] = {il,ih}
    end for
    res = sort(res[1..l])
    return res
end function

procedure test(sequence set)
    printf(1,"%40v => %v\n",{set,consolidate(set)})
end procedure

test({{1.1,2.2}})
test({{6.1,7.2},{7.2,8.3}})
test({{4,3},{2,1}})
test({{4,3},{2,1},{-1,-2},{3.9,10}})
test({{1,3},{-6,-1},{-4,-5},{8,2},{-6,-6}})


consolidate_ranges(Ranges, Consolidated):-
    normalize(Ranges, Normalized),
    sort(Normalized, Sorted),
    merge(Sorted, Consolidated).

normalize([], []):-!.
normalize([r(X, Y)|Ranges], [r(Min, Max)|Normalized]):-
    (X > Y -> Min = Y, Max = X; Min = X, Max = Y),
    normalize(Ranges, Normalized).

merge([], []):-!.
merge([Range], [Range]):-!.
merge([r(Min1, Max1), r(Min2, Max2)|Rest], Merged):-
    Min2 =< Max1,
    !,
    Max is max(Max1, Max2),
    merge([r(Min1, Max)|Rest], Merged).
merge([Range|Ranges], [Range|Merged]):-
    merge(Ranges, Merged).

write_range(r(Min, Max)):-
    writef('[%w, %w]', [Min, Max]).

write_ranges([]):-!.
write_ranges([Range]):-
    !,
    write_range(Range).
write_ranges([Range|Ranges]):-
    write_range(Range),
    write(', '),
    write_ranges(Ranges).

test_case([r(1.1, 2.2)]).
test_case([r(6.1, 7.2), r(7.2, 8.3)]).
test_case([r(4, 3), r(2, 1)]).
test_case([r(4, 3), r(2, 1), r(-1, -2), r(3.9, 10)]).
test_case([r(1, 3), r(-6, -1), r(-4, -5), r(8, 2), r(-6, -6)]).

main:-
    forall(test_case(Ranges),
           (consolidate_ranges(Ranges, Consolidated),
            write_ranges(Ranges), write(' -> '),
            write_ranges(Consolidated), nl)).


#lang racket

;; Racket's max and min allow inexact numbers to contaminate exact numbers
;; Use argmax and argmin instead, as they don't have this problem

(define (max . xs) (argmax identity xs))
(define (min . xs) (argmin identity xs))

;; a bag is a list of disjoint intervals

(define ((irrelevant? x y) item) (or (< (second item) x) (> (first item) y)))

(define (insert bag x y)
  (define-values (irrelevant relevant) (partition (irrelevant? x y) bag))
  (cons (list (apply min x (map first relevant))
              (apply max y (map second relevant))) irrelevant))

(define (solve xs)
  (sort (for/fold ([bag '()]) ([x (in-list xs)])
          (insert bag (apply min x) (apply max x))) < #:key first))

(define inputs '(([1.1 2.2])
                 ([6.1 7.2] [7.2 8.3])
                 ([4 3] [2 1])
                 ([4 3] [2 1] [-1 -2] [3.9 10])
                 ([1 3] [-6 -1] [-4 -5] [8 2] [-6 -6])))

(for ([xs (in-list inputs)]) (printf "~a => ~a\n" xs (solve xs)))


# Union
sub infix:<∪> (Range $a, Range $b) { Range.new($a.min,max($a.max,$b.max)) }

# Intersection
sub infix:<∩> (Range $a, Range $b) { so $a.max >= $b.min }

multi consolidate() { () }

multi consolidate($this is copy, **@those) {
    gather {
        for consolidate |@those -> $that {
            if $this ∩ $that { $this ∪= $that }
            else             { take $that }
        }
        take $this;
    }
}

for [[1.1, 2.2],],
    [[6.1, 7.2], [7.2, 8.3]],
    [[4, 3], [2, 1]],
    [[4, 3], [2, 1], [-1, -2], [3.9, 10]],
    [[1, 3], [-6, -1], [-4, -5], [8, 2], [-6, -6]]
-> @intervals {
    printf "%46s => ", @intervals.raku;
    say reverse consolidate |@intervals.grep(*.elems)».sort.sort({ [.[0], .[*-1]] }).map: { Range.new(.[0], .[*-1]) }
}


/*REXX program performs range consolidation (they can be [equal] ascending/descending). */
#.=                                              /*define the default for range sets.   */
parse arg #.1                                    /*obtain optional arguments from the CL*/
if #.1=''  then do                               /*Not specified?  Then use the defaults*/
                #.1= '[1.1, 2.2]'
                #.2= '[6.1, 7.2], [7.2, 8.3]'
                #.3= '[4, 3], [2, 1]'
                #.4= '[4, 3], [2, 1], [-1, -2], [3.9, 10]'
                #.5= '[1, 3], [-6, -1], [-4, -5], [8, 2], [-6, -6]'
                #.6= '[]'
                end

       do j=1  while #.j\=='';   $= #.j          /*process each of the range sets.      */
       say copies('═', 75)                       /*display a fence between range sets.  */
       say '         original ranges:'     $     /*display the original range set.      */
       $= order($)                               /*order low and high ranges; normalize.*/
       call xSort  words($)                      /*sort the ranges using a simple sort. */
       $= merge($)                               /*consolidate the ranges.              */
       say '     consolidated ranges:'     $     /*display the consolidated range set.  */
       end   /*j*/
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
merge: procedure expose @.; parse arg y
       if words(y)<2  then signal build          /*Null or only 1 range?  Skip merging. */

          do j=1  to @.0-1;         if @.j==''  then iterate      /*skip deleted ranges.*/
            do k=j+1  to  @.0;      if @.k==''  then iterate      /*  "     "       "   */
            parse var  @.j  a   b;  parse var  @.k  aa  bb        /*extract low and high*/
/*■■■■►*/   if a<=aa & b>=bb  then  do; @.k=;  iterate;            end  /*within a range*/
/*■■■■►*/   if a<=aa & b>=aa  then  do; @.j= a bb; @.k=; iterate;  end  /*abutted ranges*/
            end   /*k*/
          end     /*j*/
build: z=
             do r=1  for @.0;  z= z translate(@.r, ',', " ");  end   /*r*/   /*add comma*/
       f=;   do s=1  for words(z);   f= f '['word(z, s)"], ";  end   /*s*/   /*add [ ], */
       if f==''  then return '[]'                                            /*null set.*/
       return space( changestr(',',  strip( space(f), 'T', ","), ", ") )     /*add blank*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
order: procedure expose @.; parse arg y,,z;  @.= /*obtain arguments from the invocation.*/
       y= space(y, 0)                            /*elide superfluous blanks in the sets.*/
          do k=1  while y\==''  &  y\=='[]'      /*process ranges while range not blank.*/
          y= strip(y, 'L', ",")                  /*elide commas between sets of ranges. */
          parse var  y   '['  L  ","  H  ']'   y /*extract  the "low" and "high" values.*/
          if H<L  then parse value  L H with H L /*order     "    "    "     "      "   */
          L= L / 1;     H= H / 1                 /*normalize the  L  and the  H  values.*/
          @.k= L H;     z= z L','H               /*re─build the set w/o and with commas.*/
          end   /*k*/                            /* [↓]  at this point, K is one to big.*/
       @.0= k - 1                                /*keep track of the number of ranges.  */
       return strip(z)                           /*elide the extra leading blank in set.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
xSort: procedure expose @.; parse arg n          /*a simple sort for small set of ranges*/
          do j=1  to n-1;                        _= @.j
            do k=j+1  to n; if word(@.k,1)>=word(_,1)  then iterate; @.[email protected].k; @.k=_; [email protected].j
            end   /*k*/
          end     /*j*/;        return


use std::fmt::{Display, Formatter};

// We could use std::ops::RangeInclusive, but we would have to extend it to
// normalize self (not much trouble) and it would not have to handle pretty
// printing for it explicitly. So, let's make rather an own type.

#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct ClosedRange<Idx> {
    start: Idx,
    end: Idx,
}

impl<Idx> ClosedRange<Idx> {
    pub fn start(&self) -> &Idx {
        &self.start
    }

    pub fn end(&self) -> &Idx {
        &self.end
    }
}

impl<Idx: PartialOrd> ClosedRange<Idx> {
    pub fn new(start: Idx, end: Idx) -> Self {
        if start <= end {
            Self { start, end }
        } else {
            Self {
                end: start,
                start: end,
            }
        }
    }
}

// To make test input more compact
impl<Idx: PartialOrd> From<(Idx, Idx)> for ClosedRange<Idx> {
    fn from((start, end): (Idx, Idx)) -> Self {
        Self::new(start, end)
    }
}

// For the required print format
impl<Idx: Display> Display for ClosedRange<Idx> {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "[{}, {}]", self.start, self.end)
    }
}

fn consolidate<Idx>(a: &ClosedRange<Idx>, b: &ClosedRange<Idx>) -> Option<ClosedRange<Idx>>
where
    Idx: PartialOrd + Clone,
{
    if a.start() <= b.start() {
        if b.end() <= a.end() {
            Some(a.clone())
        } else if a.end() < b.start() {
            None
        } else {
            Some(ClosedRange::new(a.start().clone(), b.end().clone()))
        }
    } else {
        consolidate(b, a)
    }
}

fn consolidate_all<Idx>(mut ranges: Vec<ClosedRange<Idx>>) -> Vec<ClosedRange<Idx>>
where
    Idx: PartialOrd + Clone,
{
    // Panics for incomparable elements! So no NaN for floats, for instance.
    ranges.sort_by(|a, b| a.partial_cmp(b).unwrap());
    let mut ranges = ranges.into_iter();
    let mut result = Vec::new();

    if let Some(current) = ranges.next() {
        let leftover = ranges.fold(current, |mut acc, next| {
            match consolidate(&acc, &next) {
                Some(merger) => {
                    acc = merger;
                }

                None => {
                    result.push(acc);
                    acc = next;
                }
            }

            acc
        });

        result.push(leftover);
    }

    result
}

#[cfg(test)]
mod tests {
    use super::{consolidate_all, ClosedRange};
    use std::fmt::{Display, Formatter};

    struct IteratorToDisplay<F>(F);

    impl<F, I> Display for IteratorToDisplay<F>
    where
        F: Fn() -> I,
        I: Iterator,
        I::Item: Display,
    {
        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
            let mut items = self.0();

            if let Some(item) = items.next() {
                write!(f, "{}", item)?;
                for item in items {
                    write!(f, ", {}", item)?;
                }
            }

            Ok(())
        }
    }

    macro_rules! parameterized {
        ($($name:ident: $value:expr,)*) => {
            $(
                #[test]
                fn $name() {
                    let (input, expected) = $value;
                    let expected: Vec<_> = expected.into_iter().map(ClosedRange::from).collect();
                    let output = consolidate_all(input.into_iter().map(ClosedRange::from).collect());
                    println!("{}: {}", stringify!($name), IteratorToDisplay(|| output.iter()));
                    assert_eq!(expected, output);
                }
            )*
        }
    }

    parameterized! {
        single: (vec![(1.1, 2.2)], vec![(1.1, 2.2)]),
        touching: (vec![(6.1, 7.2), (7.2, 8.3)], vec![(6.1, 8.3)]),
        disjoint: (vec![(4, 3), (2, 1)], vec![(1, 2), (3, 4)]),
        overlap: (vec![(4.0, 3.0), (2.0, 1.0), (-1.0, -2.0), (3.9, 10.0)], vec![(-2.0, -1.0), (1.0, 2.0), (3.0, 10.0)]),
        integer: (vec![(1, 3), (-6, -1), (-4, -5), (8, 2), (-6, -6)], vec![(-6, -1), (1, 8)]),
    }
}

fn main() {
    // To prevent dead code and to check empty input
    consolidate_all(Vec::<ClosedRange<usize>>::new());

    println!("Run: cargo test -- --nocapture");
}


class Span {
    construct new(r) {
        if (r.type != Range || !r.isInclusive) Fiber.abort("Argument must be an inclusive range.")
        _low = r.from
        _high = r.to
        if (_low > _high) {
            _low = r.to
            _high = r.from
        }
    }

    low  { _low }
    high { _high }

    consolidate(r) {
         if (r.type != Span) Fiber.abort("Argument must be a Span.")
         if (_high < r.low) return [this, r]
         if (r.high < _low) return [r, this]
         return [Span.new(_low.min(r.low).._high.max(r.high))]
    }

    toString { "[%(_low), %(_high)]" }
}

var spanLists = [
    [Span.new(1.1..2.2)],
    [Span.new(6.1..7.2), Span.new(7.2..8.3)],
    [Span.new(4..3), Span.new(2..1)],
    [Span.new(4..3), Span.new(2..1), Span.new(-1..-2), Span.new(3.9..10)],
    [Span.new(1..3), Span.new(-6..-1), Span.new(-4..-5), Span.new(8..2), Span.new(-6..-6)]
]

for (spanList in spanLists) {
    if (spanList.count == 1) {
        System.print(spanList.toString[1..-2])
    } else if (spanList.count == 2) {
        System.print(spanList[0].consolidate(spanList[1]).toString[1..-2])
    } else {
        var first = 0
        while (first < spanList.count-1) {
            var next = first + 1
            while (next < spanList.count) {
                var res = spanList[first].consolidate(spanList[next])
                spanList[first] = res[0]
                if (res.count == 2) {
                    spanList[next] = res[1]
                    next = next + 1
                } else {
                    spanList.removeAt(next)
                }
            }
            first = first + 1
        }
        System.print(spanList.toString[1..-2])
    }
}


sub sort(tabla())
    local items, i, t1, t2, s

    items = arraysize(tabla(), 1)

    repeat
        s = true
        for i = 1 to items-1
            if tabla(i, 1) > tabla(i+1, 1) then
                t1 = tabla(i, 1) : t2 = tabla(i, 2)
                tabla(i, 1) = tabla(i + 1, 1) : tabla(i, 2) = tabla(i + 1, 2)
                tabla(i + 1, 1) = t1 : tabla(i + 1, 2) = t2
                s = false
            end if
        next
    until(s)
end sub

sub normalize(tabla())
    local items, i, t

    items = arraysize(tabla(), 1)

    for i = 1 to items
        if tabla(i, 1) > tabla(i, 2) then
            t = tabla(i, 1)
            tabla(i, 1) = tabla(i, 2)
            tabla(i, 2) = t
        end if
    next

    sort(tabla())
end sub

sub consolidate(tabla())
    local items, i

    normalize(tabla())
    items = arraysize(tabla(), 1)

    for i = 1 to items - 1
        if tabla(i + 1, 1) <= tabla(i, 2) then
            tabla(i + 1, 1) = tabla(i, 1)
            if tabla(i + 1, 2) <= tabla(i, 2) then
                tabla(i + 1, 2) = tabla(i, 2)
            end if
            tabla(i, 1) = void : tabla(i, 2) = void
        end if
    next
end sub

// data 1, 1.1, 2.2
// data 2, 6.1, 7.2, 7.2, 8.3
// data 2, 4, 3, 2, 1
// data 4, 4, 3, 2, 1, -1, -2, 3.9, 10
 data 5, 1,3, -6,-1, -4,-5, 8,2, -6,-6

void = 10^30
read items

dim tabla(items,  2)

for i = 1 to items
    read tabla(i, 1), tabla(i, 2)
next

consolidate(tabla())

for i = 1 to items
    if tabla(i, 1) <> void print tabla(i, 1), "..", tabla(i, 2);
next


fcn consolidate(rs){
   (s:=List()).append(
      normalize(rs).reduce('wrap(ab,cd){
     if(ab[1]>=cd[0]) L(ab[0],ab[1].max(cd[1])); // consolidate
     else{ s.append(ab); cd }            // no overlap
      }) )
}
fcn normalize(s){ s.apply("sort").sort(fcn(a,b){ a[0]<b[0] }) }


F mc_rank([(Int, String)] iterable)
   ‘Modified competition ranking’
   [(Float, (Int, String))] r
   V lastresult = -1
   [(Int, String)] fifo
   L(item) iterable
      I item[0] == lastresult
         fifo [+]= item
      E
         V n = L.index
         L !fifo.empty
            r.append((n, fifo.pop(0)))
         lastresult = item[0]
         fifo [+]= item
   L !fifo.empty
      r.append((iterable.len, fifo.pop(0)))
   R r

F sc_rank([(Int, String)] iterable)
   ‘Standard competition ranking’
   [(Float, (Int, String))] r
   V lastresult = -1
   V lastrank = -1
   L(item) iterable
      I item[0] == lastresult
         r.append((lastrank, item))
      E
         V n = L.index + 1
         r.append((n, item))
         lastresult = item[0]
         lastrank = n
   R r

F d_rank([(Int, String)] iterable)
   ‘Dense ranking’
   [(Float, (Int, String))] r
   V lastresult = -1
   V lastrank = 0
   L(item) iterable
      I item[0] == lastresult
         r.append((lastrank, item))
      E
         lastresult = item[0]
         lastrank++
         r.append((lastrank, item))
   R r

F o_rank([(Int, String)] iterable)
   ‘Ordinal ranking’
   R enumerate(iterable, 1).map((i, item) -> ((Float(i), item)))

F f_rank([(Int, String)] iterable)
   ‘Fractional ranking’
   [(Float, (Int, String))] r
   V last = -1
   [(Int, (Int, String))] fifo
   L(item) iterable
      I item[0] != last
         I !fifo.empty
            V mean = Float(sum(fifo.map(f -> f[0]))) / fifo.len
            L !fifo.empty
               r.append((mean, fifo.pop(0)[1]))
      last = item[0]
      fifo.append((L.index + 1, item))
   I !fifo.empty
      V mean = sum(fifo.map(f -> f[0])) / fifo.len
      L !fifo.empty
         r.append((mean, fifo.pop(0)[1]))
   R r

V scores = [(44, ‘Solomon’),
            (42, ‘Jason’),
            (42, ‘Errol’),
            (41, ‘Garry’),
            (41, ‘Bernard’),
            (41, ‘Barry’),
            (39, ‘Stephen’)]

print("\nScores to be ranked (best first):")
L(n, s) scores
   print(‘        #2 #.’.format(n, s))

L(ranker, ranking_method) [(sc_rank, ‘Standard competition ranking’),
                           (mc_rank, ‘Modified competition ranking’),
                            (d_rank, ‘Dense ranking’),
                            (o_rank, ‘Ordinal ranking’),
                            (f_rank, ‘Fractional ranking’)]
   print("\n#.:".format(ranking_method))
   L(rank, score) ranker(scores)
      print(‘  #3, (#., #.)’.format(rank, score[0], score[1]))


(*
    The five ranking methods are implemented here as script objects sharing inherited code rather than as simple
    handlers, although there appears to be little advantage either way. This way needs fewer lines of code
    but more lines of explanatory comments!
*)
use AppleScript version "2.4" -- Mac OS 10.11 (Yosemite) or later (for these 'use' commands).
use sorter : script "Custom Iterative Ternary Merge Sort" -- <https://macscripter.net/viewtopic.php?pid=194430#p194430>

script standardRanking
    -- Properties and handlers inherited or overridden by the other script objects.
    -- The 'references' are to values that won't be available until 'results' is set to a list.
    -- 'me' and 'my' refer to the script object using the code at the time.
    property results : missing value
    property startIndex : 1
    property endIndex : a reference to length of (a reference to results)
    property step : 1
    property currentRank : missing value
    property currentScore : missing value

    -- Main handler.
    on resultsFrom(theScores)
        copy theScores to my results
        -- The task description specifies that the input list is already ordered, but that's not assumed here.
        -- Additionally, competitors with equal scores are arranged alphabetically by name.
        -- The comparer here is 'me' because the current script object contains the isGreater(a, b) handler to be used.
        tell sorter to sort(my results, my startIndex, my endIndex, {comparer:me})
        set my currentScore to score of item (my startIndex) of my results
        set my currentRank to my startIndex's contents
        repeat with i from (my startIndex) to (my endIndex) by (my step)
            my rankResult(i)
        end repeat
        -- Since these script objects are assigned to top-level variables in a running script, make sure the potentially
        -- long 'results' list isn't saved back to the script file with them at the end of the run. This precaution isn't
        -- necessary in a library script or if the scripts are instantiated and assigned to local variables at run time.
        set localVariable to my results
        set my results to missing value
        return localVariable
    end resultsFrom

    -- Comparison handler used by the sort. The returned boolean indicates whether or not record 'a' should go after record 'b'.
    on isGreater(a, b)
        if (a's score is less than b's score) then return true
        return ((a's score is equal to b's score) and (a's competitor comes after b's competitor))
    end isGreater

    -- Specialist ranking handler. Inherited by the modifiedRanking script, but overridden by the others.
    on rankResult(i)
        set thisResult to item i of my results
        set thisScore to thisResult's score
        if (thisScore is not currentScore) then
            set my currentRank to i
            set my currentScore to thisScore
        end if
        set item i of my results to thisResult & {rank:my currentRank}
    end rankResult
end script

script modifiedRanking -- Uses the standardRanking code, but works backwards through the results list.
    property parent : standardRanking
    property startIndex : a reference to length of (a reference to results)
    property endIndex : 1
    property step : -1
end script

script denseRanking
    property parent : standardRanking

    on rankResult(i)
        set thisResult to item i of my results
        set thisScore to thisResult's score
        if (thisScore is not my currentScore) then
            set my currentRank to (my currentRank) + 1
            set my currentScore to thisScore
        end if
        set item i of my results to thisResult & {rank:my currentRank}
    end rankResult
end script

script ordinalRanking
    property parent : standardRanking

    on rankResult(i)
        set item i of my results to (item i of my results) & {rank:i}
    end rankResult
end script

script fractionalRanking
    property parent : standardRanking

    on rankResult(i)
        set thisResult to item i of my results
        set thisScore to thisResult's score
        if (thisScore is not my currentScore) then
            -- i and currentRank are simultaneously indices and ranks.
            -- The average of any run of consecutive integers is that of the first and last.
            set average to (i - 1 + (my currentRank)) / 2
            repeat with j from (my currentRank) to (i - 1)
                set rank of item j of my results to average
            end repeat
            set my currentRank to i
            set my currentScore to thisScore
        end if
        set item i of my results to thisResult & {rank:i as real}
    end rankResult
end script

-- Task code:
on formatRankings(type, theResults)
    set rankings to {type}
    repeat with thisResult in theResults
        set end of rankings to (thisResult's rank as text) & tab & thisResult's competitor & " (" & thisResult's score & ")"
    end repeat

    return joinStrings(rankings, linefeed)
end formatRankings

on joinStrings(listOfText, delimiter)
    set astid to AppleScript's text item delimiters
    set AppleScript's text item delimiters to delimiter
    set output to listOfText as text
    set AppleScript's text item delimiters to astid

    return output
end joinStrings

local theScores, output
set theScores to {{score:44, competitor:"Solomon"}, {score:42, competitor:"Jason"}, {score:42, competitor:"Errol"}, ¬
    {score:41, competitor:"Garry"}, {score:41, competitor:"Bernard"}, {score:41, competitor:"Barry"}, ¬
    {score:39, competitor:"Stephen"}}
set output to {}
set end of output to formatRankings("Standard ranking:", standardRanking's resultsFrom(theScores))
set end of output to formatRankings("Modified ranking:", modifiedRanking's resultsFrom(theScores))
set end of output to formatRankings("Dense ranking:", denseRanking's resultsFrom(theScores))
set end of output to formatRankings("Ordinal ranking:", ordinalRanking's resultsFrom(theScores))
set end of output to formatRankings("Fractional ranking:", fractionalRanking's resultsFrom(theScores))
return joinStrings(output, linefeed & linefeed)


Rank(data, opt:=1){ ; opt = 1 Standard (default), 2 Modified, 3 Dense, 4 Ordinal, 5 Fractional
	for index, val in StrSplit(data, "`n", "`r") {
		RegExMatch(val, "^(\d+)\s+(.*)", Match)
		if !(Match1=prev)
			n := index
		prev := Match1
		Res1 .= n "`t" Match "`n"
		Res4 .= index "`t" Match "`n"
		Temp .= n ":" index " " Match "`n"
	}
	n:=0
	while pos := RegExMatch(Temp, "`asm)^(\d+).*?\R(?!\1)|.+", Match, pos?pos+StrLen(Match):1) {
		n += StrSplit(Trim(Match, "`r`n"), "`n", "`r").MaxIndex()
		Res2 .= RegExReplace(Match, "`am)^\d+:\d+", n "`t")
		Res3 .= RegExReplace(Match, "`am)^\d+:\d+", A_Index "`t")
		R := 0
		for index, val in StrSplit(Match, "`n", "`r")
			R += StrSplit(val, ":").2
		Res5 .= RegExReplace(Match, "`am)^\d+:\d+", RegExReplace(R / StrSplit(Trim(Match, "`r`n"), "`n", "`r").MaxIndex(), "\.?0+$") "`t")
	}
	return Res%opt%
}


standard   ← ∊∘(⌊\¨⊢⊂⍳∘≢)∘(1,2≠/⊢)∘(1⌷[2]⊢),⊢
modified   ← ∊∘(⌈\∘⌽¨⊢⊂⍳∘≢)∘(1,2≠/⊢)∘(1⌷[2]⊢),⊢
dense      ← (+\1,2≠/1⌷[2]⊢),⊢
ordinal    ← ⍳∘≢,⊢
fractional ← ∊∘((≢(/∘⊢)+/÷≢)¨⊢⊂⍳∘≢)∘(1,2≠/⊢)∘(1⌷[2]⊢),⊢


##
## 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()}


10 READ N
20 DIM S(N),N$(N),R(N)
30 FOR I=1 TO N: READ S(I),N$(I): NEXT
40 PRINT "--- Standard ranking ---": GOSUB 100: GOSUB 400
50 PRINT "--- Modified ranking ---": GOSUB 150: GOSUB 400
60 PRINT "--- Dense ranking ---": GOSUB 200: GOSUB 400
70 PRINT "--- Ordinal ranking ---": GOSUB 250: GOSUB 400
80 PRINT "--- Fractional ranking ---": GOSUB 300: GOSUB 400
90 END
100 REM
101 REM ** Ordinal ranking **
110 R(1)=1
120 FOR I=2 TO N
130 IF S(I)=S(I-1) THEN R(I)=R(I-1) ELSE R(I)=I
140 NEXT: RETURN
150 REM
151 REM ** Modified ranking **
160 R(N)=N
170 FOR I=N-1 TO 1 STEP -1
180 IF S(I)=S(I+1) THEN R(I)=R(I+1) ELSE R(I)=I
190 NEXT: RETURN
200 REM
201 REM ** Dense ranking **
210 R(1)=1
220 FOR I=2 TO N: R(I)=R(I-1)-(S(I)<>S(I-1)): NEXT
230 RETURN
250 REM
251 REM ** Ordinal ranking **
260 FOR I=1 TO N: R(I)=I: NEXT: RETURN
300 REM
301 REM ** Fractional ranking **
310 I=1: J=2
320 IF J<=N THEN IF S(J-1)=S(J) THEN J=J+1: GOTO 320
330 FOR K=I TO J-1: R(K) = (I+J-1)/2: NEXT
340 I=J: J=J+1: IF I<=N THEN 320
350 RETURN
400 REM
401 REM ** Print the table ***
410 FOR I=1 TO N
420 PRINT USING "\  \ ##, \        \";STR$(R(I));S(I);N$(I)
430 NEXT
440 PRINT: RETURN
500 DATA 7
510 DATA 44,Solomon
520 DATA 42,Jason
530 DATA 42,Errol
540 DATA 41,Garry
550 DATA 41,Bernard
560 DATA 41,Barry
570 DATA 39,Stephen


#include<stdlib.h>
#include<stdio.h>

typedef struct{
	int score;
	char name[100];
}entry;

void ordinalRanking(entry* list,int len){

	int i;

	printf("\n\nOrdinal Ranking\n---------------");

	for(i=0;i<len;i++)
		printf("\n%d\t%d\t%s",i+1,list[i].score,list[i].name);
}

void standardRanking(entry* list,int len){

	int i,j=1;

	printf("\n\nStandard Ranking\n----------------");

	for(i=0;i<len;i++){
		printf("\n%d\t%d\t%s",j,list[i].score,list[i].name);
		if(list[i+1].score<list[i].score)
			j = i+2;
	}
}

void denseRanking(entry* list,int len){

	int i,j=1;

	printf("\n\nDense Ranking\n-------------");

	for(i=0;i<len;i++){
		printf("\n%d\t%d\t%s",j,list[i].score,list[i].name);
		if(list[i+1].score<list[i].score)
			j++;
	}
}

void modifiedRanking(entry* list,int len){

	int i,j,count;

	printf("\n\nModified Ranking\n----------------");

	for(i=0;i<len-1;i++){
		if(list[i].score!=list[i+1].score){
			printf("\n%d\t%d\t%s",i+1,list[i].score,list[i].name);
			count = 1;
			for(j=i+1;list[j].score==list[j+1].score && j<len-1;j++)
				count ++;
			for(j=0;j<count-1;j++)
				printf("\n%d\t%d\t%s",i+count+1,list[i+j+1].score,list[i+j+1].name);
			i += (count-1);
		}
	}
	printf("\n%d\t%d\t%s",len,list[len-1].score,list[len-1].name);
}

void fractionalRanking(entry* list,int len){

	int i,j,count;
	float sum = 0;

	printf("\n\nFractional Ranking\n------------------");

	for(i=0;i<len;i++){
		if(i==len-1 || list[i].score!=list[i+1].score)
			printf("\n%.1f\t%d\t%s",(float)(i+1),list[i].score,list[i].name);
		else if(list[i].score==list[i+1].score){
			sum = i;
			count = 1;
			for(j=i;list[j].score==list[j+1].score;j++){
				sum += (j+1);
				count ++;
			}
			for(j=0;j<count;j++)
				printf("\n%.1f\t%d\t%s",sum/count + 1,list[i+j].score,list[i+j].name);
			i += (count-1);
		}
	}
}

void processFile(char* fileName){
	FILE* fp = fopen(fileName,"r");
	entry* list;
	int i,num;

	fscanf(fp,"%d",&num);

	list = (entry*)malloc(num*sizeof(entry));

	for(i=0;i<num;i++)
		fscanf(fp,"%d%s",&list[i].score,list[i].name);

	fclose(fp);

	ordinalRanking(list,num);
	standardRanking(list,num);
	denseRanking(list,num);
	modifiedRanking(list,num);
	fractionalRanking(list,num);
}

int main(int argC,char* argV[])
{
	if(argC!=2)
		printf("Usage %s <score list file>");
	else
		processFile(argV[1]);
	return 0;
}


using System;
using System.Collections.Generic;
using System.Linq;

namespace RankingMethods {
    class Program {
        static void Main(string[] args) {
            Dictionary<string, int> scores = new Dictionary<string, int> {
                ["Solomon"] = 44,
                ["Jason"] = 42,
                ["Errol"] = 42,
                ["Gary"] = 41,
                ["Bernard"] = 41,
                ["Barry"] = 41,
                ["Stephen"] = 39,
            };

            StandardRank(scores);
            ModifiedRank(scores);
            DenseRank(scores);
            OrdinalRank(scores);
            FractionalRank(scores);
        }

        static void StandardRank(Dictionary<string, int> data) {
            Console.WriteLine("Standard Rank");

            var list = data.Values.Distinct().ToList();
            list.Sort((a, b) => b.CompareTo(a));

            int rank = 1;
            foreach (var value in list) {
                int temp = rank;
                foreach (var k in data.Keys) {
                    if (data[k] == value) {
                        Console.WriteLine("{0} {1} {2}", temp, value, k);
                        rank++;
                    }
                }
            }

            Console.WriteLine();
        }

        static void ModifiedRank(Dictionary<string, int> data) {
            Console.WriteLine("Modified Rank");

            var list = data.Values.Distinct().ToList();
            list.Sort((a, b) => b.CompareTo(a));

            int rank = 0;
            foreach (var value in list) {
                foreach (var k in data.Keys) {
                    if (data[k] == value) {
                        rank++;
                    }
                }

                foreach (var k in data.Keys) {
                    if (data[k] == value) {
                        Console.WriteLine("{0} {1} {2}", rank, data[k], k);
                    }
                }
            }

            Console.WriteLine();
        }

        static void DenseRank(Dictionary<string, int> data) {
            Console.WriteLine("Dense Rank");

            var list = data.Values.Distinct().ToList();
            list.Sort((a, b) => b.CompareTo(a));

            int rank = 1;
            foreach (var value in list) {
                foreach (var k in data.Keys) {
                    if (data[k] == value) {
                        Console.WriteLine("{0} {1} {2}", rank, data[k], k);
                    }
                }
                rank++;
            }

            Console.WriteLine();
        }

        static void OrdinalRank(Dictionary<string, int> data) {
            Console.WriteLine("Ordinal Rank");

            var list = data.Values.Distinct().ToList();
            list.Sort((a, b) => b.CompareTo(a));

            int rank = 1;
            foreach (var value in list) {
                foreach (var k in data.Keys) {
                    if (data[k] == value) {
                        Console.WriteLine("{0} {1} {2}", rank, data[k], k);
                        rank++;
                    }
                }
            }

            Console.WriteLine();
        }

        static void FractionalRank(Dictionary<string, int> data) {
            Console.WriteLine("Fractional Rank");

            var list = data.Values.Distinct().ToList();
            list.Sort((a, b) => b.CompareTo(a));

            int rank = 0;
            foreach (var value in list) {
                double avg = 0;
                int cnt = 0;

                foreach (var k in data.Keys) {
                    if (data[k] == value) {
                        rank++;
                        cnt++;
                        avg += rank;
                    }
                }
                avg /= cnt;

                foreach (var k in data.Keys) {
                    if (data[k] == value) {
                        Console.WriteLine("{0:F1} {1} {2}", avg, data[k], k);
                    }
                }
            }

            Console.WriteLine();
        }
    }
}


#include <algorithm>
#include <iomanip>
#include <iostream>
#include <map>
#include <ostream>
#include <set>
#include <vector>

template<typename T>
std::ostream& print(std::ostream& os, const T& src) {
    auto it = src.cbegin();
    auto end = src.cend();

    os << "[";
    if (it != end) {
        os << *it;
        it = std::next(it);
    }
    while (it != end) {
        os << ", " << *it;
        it = std::next(it);
    }

    return os << "]";
}

typedef std::map<std::string, int> Map;
typedef Map::value_type MapEntry;

void standardRank(const Map& scores) {
    std::cout << "Standard Rank" << std::endl;

    std::vector<int> list;
    for (auto& elem : scores) {
        list.push_back(elem.second);
    }
    std::sort(list.begin(), list.end(), std::greater<int>{});
    list.erase(std::unique(list.begin(), list.end()), list.end());

    int rank = 1;
    for (auto value : list) {
        int temp = rank;
        for (auto& e : scores) {
            if (e.second == value) {
                std::cout << temp << " " << value << " " << e.first.c_str() << std::endl;
                rank++;
            }
        }
    }

    std::cout << std::endl;
}

void modifiedRank(const Map& scores) {
    std::cout << "Modified Rank" << std::endl;

    std::vector<int> list;
    for (auto& elem : scores) {
        list.push_back(elem.second);
    }
    std::sort(list.begin(), list.end(), std::greater<int>{});
    list.erase(std::unique(list.begin(), list.end()), list.end());

    int rank = 0;
    for (auto value : list) {
        rank += std::count_if(scores.begin(), scores.end(), [value](const MapEntry& e) { return e.second == value; });
        for (auto& e : scores) {
            if (e.second == value) {
                std::cout << rank << " " << value << " " << e.first.c_str() << std::endl;
            }
        }
    }

    std::cout << std::endl;
}

void denseRank(const Map& scores) {
    std::cout << "Dense Rank" << std::endl;

    std::vector<int> list;
    for (auto& elem : scores) {
        list.push_back(elem.second);
    }
    std::sort(list.begin(), list.end(), std::greater<int>{});
    list.erase(std::unique(list.begin(), list.end()), list.end());

    int rank = 1;
    for (auto value : list) {
        for (auto& e : scores) {
            if (e.second == value) {
                std::cout << rank << " " << value << " " << e.first.c_str() << std::endl;
            }
        }
        rank++;
    }

    std::cout << std::endl;
}

void ordinalRank(const Map& scores) {
    std::cout << "Ordinal Rank" << std::endl;

    std::vector<int> list;
    for (auto& elem : scores) {
        list.push_back(elem.second);
    }
    std::sort(list.begin(), list.end(), std::greater<int>{});
    list.erase(std::unique(list.begin(), list.end()), list.end());

    int rank = 1;
    for (auto value : list) {
        for (auto& e : scores) {
            if (e.second == value) {
                std::cout << rank++ << " " << value << " " << e.first.c_str() << std::endl;
            }
        }
    }

    std::cout << std::endl;
}

void fractionalRank(const Map& scores) {
    std::cout << "Ordinal Rank" << std::endl;

    std::vector<int> list;
    for (auto& elem : scores) {
        list.push_back(elem.second);
    }
    std::sort(list.begin(), list.end(), std::greater<int>{});
    list.erase(std::unique(list.begin(), list.end()), list.end());

    int rank = 0;
    for (auto value : list) {
        double avg = 0.0;
        int cnt = 0;

        for (auto& e : scores) {
            if (e.second == value) {
                rank++;
                cnt++;
                avg += rank;
            }
        }
        avg /= cnt;

        for (auto& e : scores) {
            if (e.second == value) {
                std::cout << std::setprecision(1) << std::fixed << avg << " " << value << " " << e.first.c_str() << std::endl;
            }
        }
    }

    std::cout << std::endl;
}

int main() {
    using namespace std;

    map<string, int> scores{
        {"Solomon", 44},
        {"Jason", 42},
        {"Errol", 42},
        {"Gary", 41},
        {"Bernard", 41},
        {"Barry", 41},
        {"Stephen", 39}
    };

    standardRank(scores);
    modifiedRank(scores);
    denseRank(scores);
    ordinalRank(scores);
    fractionalRank(scores);

    return 0;
}


include "cowgol.coh";

# List of competitors
record Competitor is
    score: uint8;
    name: [uint8];
end record;

var cs: Competitor[] := {
    {44, "Solomon"},
    {42, "Jason"},
    {42, "Errol"},
    {41, "Garry"},
    {41, "Bernard"},
    {41, "Barry"},
    {39, "Stephen"}
};

# Rank competitors given ranking method
interface Ranking(c: [Competitor],
                  n: intptr,
                  len: intptr,
                  last: uint16): (rank: uint16);
sub Rank(cs: [Competitor], num: intptr, r: Ranking) is
    var last: uint16 := 0;
    var idx: intptr := 0;

    while idx < num loop
        last := r(cs, idx, num, last);
        if last < 100 then
            print_i16(last);
        else
            # print fixed-point rank nicely
            print_i16(last / 100);
            print_char('.');
            print_i16((last % 100) / 10);
            print_i16(last % 10);
        end if;
        print(". ");
        print_i8(cs.score);
        print(", ");
        print(cs.name);
        print_nl();
        idx := idx + 1;
        cs := @next cs;
    end loop;
end sub;

# Standard ranking
var stdcount: uint16 := 0;
sub Standard implements Ranking is
    if n==0 then stdcount := 0; end if;
    stdcount := stdcount + 1;
    if n>0 and c.score == [@prev c].score then
        rank := last;
    else
        rank := stdcount;
    end if;
end sub;

# Modified ranking
sub Modified implements Ranking is
    rank := last;
    if n == 0 or c.score != [@prev c].score then
        while n < len loop
            rank := rank + 1;
            c := @next c;
            if c.score != [@prev c].score then
                break;
            end if;
            n := n + 1;
        end loop;
    end if;
end sub;

# Dense ranking
sub Dense implements Ranking is
    if n>0 and c.score == [@prev c].score then
        rank := last;
    else
        rank := last + 1;
    end if;
end sub;

# Ordinal ranking
sub Ordinal implements Ranking is
    rank := last + 1;
end sub;

# Fractional ranking (with fixed point arithmetic)
sub Fractional implements Ranking is
    rank := last;
    if n==0 or c.score != [@prev c].score then
        var sum: uint16 := 0;
        var ct: uint16 := 0;
        while n < len loop
            sum := sum + (n as uint16 + 1);
            ct := ct + 1;
            c := @next c;
            if c.score != [@prev c].score then
                break;
            end if;
            n := n + 1;
        end loop;
        rank := (sum * 100) / (ct as uint16);
    end if;
end sub;

record Method is
    name: [uint8];
    method: Ranking;
end record;

var methods: Method[] := {
    {"Standard", Standard},
    {"Modified", Modified},
    {"Dense", Dense},
    {"Ordinal", Ordinal},
    {"Fractional", Fractional}
};

var n: @indexof methods := 0;
while n < @sizeof methods loop
    print("--- ");
    print(methods[n].name);
    print(" ---\n");
    Rank(&cs[0], @sizeof cs, methods[n].method);
    print_nl();
    n := n + 1;
end loop;


import std.algorithm;
import std.stdio;

void main() {
    immutable scores = [
        "Solomon": 44,
        "Jason": 42,
        "Errol": 42,
        "Garry": 41,
        "Bernard": 41,
        "Barry": 41,
        "Stephen": 39
    ];

    scores.standardRank;
    scores.modifiedRank;
    scores.denseRank;
    scores.ordinalRank;
    scores.fractionalRank;
}

/*
Standard ranking
1 44 Solomon
2 42 Jason
2 42 Errol
4 41 Garry
4 41 Bernard
4 41 Barry
7 39 Stephen
*/
void standardRank(const int[string] data) {
    writeln("Standard Rank");

    int rank = 1;
    foreach (value; data.values.dup.sort!"a>b".uniq) {
        int temp = rank;
        foreach(k,v; data) {
            if (v==value) {
                writeln(temp, " ", v, " ", k);
                rank++;
            }
        }
    }

    writeln;
}

/*
Modified ranking
1 44 Solomon
3 42 Jason
3 42 Errol
6 41 Garry
6 41 Bernard
6 41 Barry
7 39 Stephen
*/
void modifiedRank(const int[string] data) {
    writeln("Modified Rank");

    int rank = 0;
    foreach (value; data.values.dup.sort!"a>b".uniq) {
        foreach(k,v; data) {
            if (v==value) {
                rank++;
            }
        }
        foreach(k,v; data) {
            if (v==value) {
                writeln(rank, " ", v, " ", k);
            }
        }
    }

    writeln;
}

/*
Dense ranking
1 44 Solomon
2 42 Jason
2 42 Errol
3 41 Garry
3 41 Bernard
3 41 Barry
4 39 Stephen
*/
void denseRank(const int[string] data) {
    writeln("Dense Rank");

    int rank = 1;
    foreach (value; data.values.dup.sort!"a>b".uniq) {
        foreach(k,v; data) {
            if (v==value) {
                writeln(rank, " ", v, " ", k);
            }
        }
        rank++;
    }

    writeln;
}

/*
Ordinal ranking
1 44 Solomon
2 42 Jason
3 42 Errol
4 41 Garry
5 41 Bernard
6 41 Barry
7 39 Stephen
*/
void ordinalRank(const int[string] data) {
    writeln("Ordinal Rank");

    int rank = 1;
    foreach (value; data.values.dup.sort!"a>b".uniq) {
        foreach(k,v; data) {
            if (v==value) {
                writeln(rank, " ", v, " ", k);
                rank++;
            }
        }
    }

    writeln;
}

/*
Fractional ranking
1,0 44 Solomon
2,5 42 Jason
2,5 42 Errol
5,0 41 Garry
5,0 41 Bernard
5,0 41 Barry
7,0 39 Stephen
*/
void fractionalRank(const int[string] data) {
    writeln("Fractional Rank");

    int rank = 0;
    foreach (value; data.values.dup.sort!"a>b".uniq) {
        real avg = 0;
        int cnt;

        foreach(k,v; data) {
            if (v==value) {
                rank++;
                cnt++;
                avg+=rank;
            }
        }
        avg /= cnt;

        foreach(k,v; data) {
            if (v==value) {
                writef("%0.1f ", avg);
                writeln(v, " ", k);
            }
        }
    }

    writeln;
}


defmodule Ranking do
  def methods(data) do
    IO.puts "stand.\tmod.\tdense\tord.\tfract."
    Enum.group_by(data, fn {score,_name} -> score end)
    |> Enum.map(fn {score,pairs} ->
         names = Enum.map(pairs, fn {_,name} -> name end) |> Enum.reverse
         {score, names}
       end)
    |> Enum.sort_by(fn {score,_} -> -score end)
    |> Enum.with_index
    |> Enum.reduce({1,0,0}, fn {{score, names}, i}, {s_rnk, m_rnk, o_rnk} ->
         d_rnk = i + 1
         m_rnk = m_rnk + length(names)
         f_rnk = ((s_rnk + m_rnk) / 2) |> to_string |> String.replace(".0","")
         o_rnk = Enum.reduce(names, o_rnk, fn name,acc ->
           IO.puts "#{s_rnk}\t#{m_rnk}\t#{d_rnk}\t#{acc+1}\t#{f_rnk}\t#{score} #{name}"
           acc + 1
         end)
         {s_rnk+length(names), m_rnk, o_rnk}
       end)
  end
end

~w"44 Solomon
   42 Jason
   42 Errol
   41 Garry
   41 Bernard
   41 Barry
   39 Stephen"
|> Enum.chunk(2)
|> Enum.map(fn [score,name] -> {String.to_integer(score),name} end)
|> Ranking.methods


USING: arrays assocs formatting fry generalizations io kernel
math math.ranges math.statistics math.vectors sequences
splitting.monotonic ;
IN: rosetta-code.ranking

CONSTANT: ranks {
    { 44 "Solomon" } { 42 "Jason" } { 42 "Errol" }
    { 41 "Garry" } { 41 "Bernard" } { 41 "Barry" }
    { 39 "Stephen" }
}

: rank ( seq quot -- seq' )
    '[ [ = ] monotonic-split [ length ] map dup @ [ <array> ]
    2map concat ] call ; inline

: standard ( seq -- seq' ) [ cum-sum0 1 v+n ] rank ;
: modified ( seq -- seq' ) [ cum-sum ] rank ;
: dense    ( seq -- seq' ) [ length [1,b] ] rank ;
: ordinal  ( seq -- seq' ) length [1,b] ;

: fractional ( seq -- seq' )
    [ dup cum-sum swap [ dupd - [a,b) mean ] 2map ] rank ;

: .rank ( quot -- )
    [ ranks dup keys ] dip call swap
    [ first2 "%5u %d %s\n" printf ] 2each ; inline

: ranking-demo ( -- )
    "Standard ranking"   [ standard   ]
    "Modified ranking"   [ modified   ]
    "Dense ranking"      [ dense      ]
    "Ordinal ranking"    [ ordinal    ]
    "Fractional ranking" [ fractional ]
    [ [ print ] [ .rank nl ] bi* ] 2 5 mnapply ;

MAIN: ranking-demo


Data 44,"Solomon", 42,"Jason", 42,"Errol", 41,"Garry"
Data 41,"Bernard", 41,"Barry", 39,"Stephen"

Dim Shared As Integer n = 7
Dim Shared As Integer puntos(n), i
Dim Shared As Single ptosnom(n)
Dim Shared As String nombre(n)

Print "Puntuaciones a clasificar (mejores primero):"
For i = 1 To n
    Read puntos(i), nombre(i)
    Print Using "      ##, \        \"; puntos(i); nombre(i)
Next i
Print

Sub MostarTabla
    For i = 1 To n
        Print Using " \  \ ##, \        \"; Str(ptosnom(i)); puntos(i); nombre(i)
    Next i
    Print
End Sub

Print "--- Standard ranking ---"
ptosnom(1) = 1
For i = 2 To n
    If puntos(i) = puntos(i-1) Then ptosnom(i) = ptosnom(i-1) Else ptosnom(i) = i
Next i
MostarTabla

Print "--- Modified ranking ---"
ptosnom(n) = n
For i = n-1 To 1 Step -1
    If puntos(i) = puntos(i+1) Then ptosnom(i) = ptosnom(i+1) Else ptosnom(i) = i
Next i
MostarTabla

Print "--- Dense ranking ---"
ptosnom(1) = 1
For i = 2 To n
    ptosnom(i) = ptosnom(i-1) - (puntos(i) <> puntos(i-1))
Next i
MostarTabla

Print "--- Ordinal ranking ---"
For i = 1 To n
    ptosnom(i) = i
Next i
MostarTabla

Print "--- Fractional ranking ---"
i = 1
Dim As Integer j = 2
Do
    If j <= n Then If (puntos(j-1) = puntos(j)) Then j += 1
    For k As Integer = i To j-1
        ptosnom(k) = (i+j-1) / 2
    Next k
    i = j
    j += 1
Loop While i <= n
MostarTabla
Sleep


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)
}


import Data.List (groupBy, sortBy, 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 . sortBy (flip compare)
  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) = (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 (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


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 :'<"[email protected]@:scores,.]'


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]);
        }
    }
}


(function () {

    var xs = 'Solomon Jason Errol Garry Bernard Barry Stephen'.split(' '),
        ns = [44, 42, 42, 41, 41, 41, 39],

        sorted = xs.map(function (x, i) {
            return { name: x, score: ns[i] };
        }).sort(function (a, b) {
            var c = b.score - a.score;
            return c ? c : a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
        }),

        names = sorted.map(function (x) { return x.name; }),
        scores = sorted.map(function (x) { return x.score; }),

        reversed = scores.slice(0).reverse(),
        unique = scores.filter(function (x, i) {
            return scores.indexOf(x) === i;
        });

    // RANKINGS AS FUNCTIONS OF SCORES: SORTED, REVERSED AND UNIQUE

    var rankings = function (score, index) {
            return {
                name: names[index],
                score: score,

                Ordinal: index + 1,

                Standard: function (n) {
                    return scores.indexOf(n) + 1;
                }(score),

                Modified: function (n) {
                    return reversed.length - reversed.indexOf(n);
                }(score),

                Dense: function (n) {
                    return unique.indexOf(n) + 1;
                }(score),

                Fractional: function (n) {
                    return (
                        (scores.indexOf(n) + 1) +
                        (reversed.length - reversed.indexOf(n))
                    ) / 2;
                }(score)
            };
        },

        tbl = [
            'Name Score Standard Modified Dense Ordinal Fractional'.split(' ')
        ].concat(scores.map(rankings).reduce(function (a, x) {
            return a.concat([
                [x.name, x.score,
                    x.Standard, x.Modified, x.Dense, x.Ordinal, x.Fractional
                ]
            ]);
        }, [])),

        //[[a]] -> bool -> s -> s
        wikiTable = function (lstRows, blnHeaderRow, strStyle) {
            return '{| class="wikitable" ' + (
                strStyle ? 'style="' + strStyle + '"' : ''
            ) + lstRows.map(function (lstRow, iRow) {
                var strDelim = ((blnHeaderRow && !iRow) ? '!' : '|');

                return '\n|-\n' + strDelim + ' ' + lstRow.map(function (v) {
                    return typeof v === 'undefined' ? ' ' : v;
                }).join(' ' + strDelim + strDelim + ' ');
            }).join('') + '\n|}';
        };

    return wikiTable(tbl, true, 'text-align:center');

})();


[ player1, score1, player2, score2, ...]


function ties{T<:Real}(a::Array{T,1})
    unique(a[2:end][a[2:end] .== a[1:end-1]])
end


// version 1.0.6

/* all ranking functions assume the array of Pairs is non-empty and already sorted by decreasing order of scores
   and then, if the scores are equal, by reverse alphabetic order of names
*/

fun standardRanking(scores: Array<Pair<Int, String>>): IntArray {
    val rankings = IntArray(scores.size)
    rankings[0] = 1
    for (i in 1 until scores.size) rankings[i] = if (scores[i].first == scores[i - 1].first) rankings[i - 1] else i + 1
    return rankings
}

fun modifiedRanking(scores: Array<Pair<Int, String>>): IntArray {
    val rankings = IntArray(scores.size)
    rankings[0] = 1
    for (i in 1 until scores.size) {
        rankings[i] = i + 1
        val currScore = scores[i].first
        for (j in i - 1 downTo 0) {
            if (currScore != scores[j].first) break
            rankings[j] = i + 1
        }
    }
    return rankings
}

fun denseRanking(scores: Array<Pair<Int, String>>): IntArray {
    val rankings = IntArray(scores.size)
    rankings[0] = 1
    var prevRanking = 1
    for (i in 1 until scores.size) rankings[i] = if (scores[i].first == scores[i - 1].first) prevRanking else ++prevRanking
    return rankings
}

fun ordinalRanking(scores: Array<Pair<Int, String>>) = IntArray(scores.size) { it + 1 }

fun fractionalRanking(scores: Array<Pair<Int, String>>): DoubleArray {
    val rankings = DoubleArray(scores.size)
    rankings[0] = 1.0
    for (i in 1 until scores.size) {
        var k = i
        val currScore = scores[i].first
        for (j in i - 1 downTo 0) {
            if (currScore != scores[j].first) break
            k = j
        }
        val avg = (k..i).average() + 1.0
        for (m in k..i) rankings[m] = avg
    }
    return rankings
}

fun printRankings(title: String, rankings: IntArray, scores: Array<Pair<Int, String>>) {
    println(title + ":")
    for (i in 0 until rankings.size) {
        print ("${rankings[i]}  ")
        println(scores[i].toString().removeSurrounding("(", ")").replace(",", ""))
    }
    println()
}

fun printFractionalRankings(title: String, rankings: DoubleArray, scores: Array<Pair<Int, String>>) {
    println(title + ":")
    for (i in 0 until rankings.size) {
        print ("${"%3.2f".format(rankings[i])}  ")
        println(scores[i].toString().removeSurrounding("(", ")").replace(",", ""))
    }
    println()
}

fun main(args: Array<String>) {
    val scores = arrayOf(44 to "Solomon",  42 to "Jason", 42 to "Errol",  41 to "Garry",
                         41 to "Bernard",  41 to "Barry", 39 to "Stephen")
    printRankings("Standard ranking", standardRanking(scores), scores)
    printRankings("Modified ranking", modifiedRanking(scores), scores)
    printRankings("Dense ranking", denseRanking(scores), scores)
    printRankings("Ordinal ranking", ordinalRanking(scores), scores)
    printFractionalRankings("Fractional ranking", fractionalRanking(scores), scores)
}


#!/bin/ksh
exec 2> /tmp/Ranking_methods.err
# Ranking methods
#
#	# 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)

#	# Variables:
#
typeset -a arr=( '44 Solomon' '42 Jason' '42 Errol' '41 Garry' '41 Bernard' '41 Barry' '39 Stephen' )
integer i

#	# Functions:
#

#	# Function _rankStandard(arr, rankarr) - retun arr with standard ranking
#
function _rankStandard {
	typeset _ranked ; nameref _ranked="$1"

	typeset _i _j _scr _currank _prevscr _shelf
	integer _i _j _scr _currank=1 _prevscr
	typeset -a _shelf

	for ((_i=0; _i<${#arr[*]}; _i++)); do
		_scr=${arr[_i]%\ *}
		if (( _i>0 )) && (( _scr != _prevscr )); then
			for ((_j=0; _j<${#_shelf[*]}; _j++)); do
				_ranked+=( "${_currank} ${_shelf[_j]}" )
			done
			(( _currank+=${#_shelf[*]} ))
			unset _shelf ; typeset -a _shelf
		fi
		_shelf+=( "${arr[_i]}" )
		_prevscr=${_scr}
	done
	for ((_j=0; _j<${#_shelf[*]}; _j++)); do
		_ranked+=( "${_currank} ${_shelf[_j]}" )
	done
}

#	# Function _rankModified(arr, rankarr) - retun arr with modified ranking
#
function _rankModified {
	typeset _ranked ; nameref _ranked="$1"

	typeset _i _j _scr _currank _prevscr _shelf
	integer _i _j _scr _currank=0 _prevscr
	typeset -a _shelf

	for ((_i=0; _i<${#arr[*]}; _i++)); do
		_scr=${arr[_i]%\ *}
		if (( _i>0 )) && (( _scr != _prevscr )); then
			for ((_j=0; _j<${#_shelf[*]}; _j++)); do
				_ranked+=( "${_currank} ${_shelf[_j]}" )
			done
			unset _shelf ; typeset -a _shelf
		fi
		_shelf+=( "${arr[_i]}" )
		(( _currank++ ))
		_prevscr=${_scr}
	done
	for ((_j=0; _j<${#_shelf[*]}; _j++)); do
		_ranked+=( "${_currank} ${_shelf[_j]}" )
	done
}

#	# Function _rankDense(arr, rankarr) - retun arr with dense ranking
#
function _rankDense {
	typeset _ranked ; nameref _ranked="$1"

	typeset _i _j _scr _currank _prevscr _shelf
	integer _i _j _scr _currank=0 _prevscr
	typeset -a _shelf

	for ((_i=0; _i<${#arr[*]}; _i++)); do
		_scr=${arr[_i]%\ *}
		if (( _i>0 )) && (( _scr != _prevscr )); then
			(( _currank++ ))
			for ((_j=0; _j<${#_shelf[*]}; _j++)); do
				_ranked+=( "${_currank} ${_shelf[_j]}" )
			done
			unset _shelf ; typeset -a _shelf
		fi
		_shelf+=( "${arr[_i]}" )
		_prevscr=${_scr}
	done
	(( _currank++ ))
	for ((_j=0; _j<${#_shelf[*]}; _j++)); do
		_ranked+=( "${_currank} ${_shelf[_j]}" )
	done
}

#	# Function _rankOrdinal(arr, rankarr) - retun arr with ordinal ranking
#
function _rankOrdinal {
	typeset _ranked ; nameref _ranked="$1"
	typeset _i ; integer _i

	for ((_i=0; _i<${#arr[*]}; _i++)); do
		_ranked+=( "$(( _i + 1 )) ${arr[_i]}" )
	done
}

#	# Function _rankFractional(arr, rankarr) - retun arr with Fractional ranking
#
function _rankFractional {
	typeset _ranked ; nameref _ranked="$1"

	typeset _i _j _scr _currank _prevscr _shelf
	integer _i _j _scr _prevscr
	typeset -F1 _currank=1.0
	typeset -a _shelf

	for ((_i=0; _i<${#arr[*]}; _i++)); do
		_scr=${arr[_i]%\ *}
		if (( _i>0 )) && (( _scr != _prevscr )); then
			(( _currank/=${#_shelf[*]} ))
			for ((_j=0; _j<${#_shelf[*]}; _j++)); do
				_ranked+=( "${_currank} ${_shelf[_j]}" )
			done
			_currank=0.0
			unset _shelf ; typeset -a _shelf
		fi
		(( _i>0 )) && (( _currank+=_i + 1 ))
		_shelf+=( "${arr[_i]}" )
		_prevscr=${_scr}
	done
	for ((_j=0; _j<${#_shelf[*]}; _j++)); do
		(( _currank/=${#_shelf[*]} ))
		_ranked+=( "${_currank} ${_shelf[_j]}" )
	done
}

 ######
# main #
 ######

printf "\n\nInput Data: ${#arr[*]} records\n---------------------\n"
for ((i=0; i< ${#arr[*]}; i++)); do
	print ${arr[i]}
done

typeset -a rankedarr
_rankStandard rankedarr
printf "\n\nStandard Ranking\n----------------\n"
for ((i=0; i< ${#rankedarr[*]}; i++)); do
	print ${rankedarr[i]}
done

unset rankedarr ; typeset -a rankedarr
_rankModified rankedarr
printf "\n\nModified Ranking\n----------------\n"
for ((i=0; i< ${#rankedarr[*]}; i++)); do
	print ${rankedarr[i]}
done

unset rankedarr ; typeset -a rankedarr
_rankDense rankedarr
printf "\n\nDense Ranking\n-------------\n"
for ((i=0; i< ${#rankedarr[*]}; i++)); do
	print ${rankedarr[i]}
done

unset rankedarr ; typeset -a rankedarr
_rankOrdinal rankedarr
printf "\n\nOrdinal Ranking\n---------------\n"
for ((i=0; i< ${#rankedarr[*]}; i++)); do
	print ${rankedarr[i]}
done

unset rankedarr ; typeset -a rankedarr
_rankFractional rankedarr
printf "\n\nFractional Ranking\n------------------\n"
for ((i=0; i< ${#rankedarr[*]}; i++)); do
	print ${rankedarr[i]}
done


Module Ranking (output$, orderlist) {
	Open output$ for output as #k
	Gosub getdata
	Print #k, "Standard ranking:"
	skip=true
	rankval=1
	oldrank=0
	For i=1 to items
		Read rank, name$
		if skip then
			skip=false
		else.if oldrank<>rank then
			rankval=i
		end if
		oldrank=rank
		Print #k, Format$("{0::-5} {2} ({1})", rankval, rank, name$)
	Next
	Gosub getdata
	Print #k,  "Modified ranking:"
	skip=true
	rankval=Items
	oldrank=0
	ShiftBack 1, -items*2  ' reverse stack items
	For i=items to 1
		Read name$, rank
		if skip then
			skip=false
		else.if oldrank<>rank then
			rankval=i
		end if
		oldrank=rank
		Data Format$("{0::-5} {2} ({1})", rankval, rank, name$)
	Next
	ShiftBack 1, -items  ' reverse stack items
	For i=1 to items
		Print #k, letter$
	Next i
	Gosub getdata
	Print #k, "Dense ranking:"
	skip=true
	Dense=Stack
	acc=1
	oldrank=0
	For i=1 to items
		Read rank, name$
		if skip then
			skip=false
			oldrank=rank
		else.if  oldrank<>rank then
			oldrank=rank
			Gosub dense
			acc=i
		end if
		Stack Dense {data Format$(" {0} ({1})",name$, rank)}
	Next
	Gosub dense
	Gosub getdata
	Print #k, "Ordinal ranking:"
	For i=1 to items
		Print #k, Format$("{0::-5} {2} ({1})", i, Number, letter$)
	Next
	Gosub getdata
	Print #k, "Fractional ranking:"
	skip=true
	Frac=Stack
	acc=1
	oldrank=0
	For i=1 to items
		Read rank, name$
		if skip then
			skip=false
			oldrank=rank
		else.if  oldrank<>rank then
			oldrank=rank
			Gosub Fractional
			acc=I
		end if
		Stack Frac {data Format$(" {0} ({1})",name$, rank)}
	Next
	Gosub Fractional
	Close #k
	End
	Fractional:
		val=((len(Frac)+1)/2+(acc-1))
		Stack Frac {
			while not empty
				Print #k, format$("{0:1:-5}{1}", val, letter$)
			end while
		}
	Return
	dense:
		Stack Dense {
			while not empty
				Print #k, format$("{0::-5}{1}", acc, letter$)
			end while
		}
	Return
	getdata:
		flush
		stack stack(orderlist)  // place a copy of items to current stack
		items=stack.size/2
	Return
}
Flush
Data 44, "Solomon", 42, "Jason", 42, "Errol"
Data 41, "Garry", 41, "Bernard", 41, "Barry"
Data 39, "Stephen"
// get all items from current stack to a new stack
alist=[]
// To screen
Ranking "", alist
// To file
Ranking "ranking.txt", alist


data = [email protected]{{44, 42, 42, 41, 41, 41, 39}, {"Solomon", "Jason",
     "Errol", "Garry", "Bernard", "Barry", "Stephen"}};

rank[data_, type_] :=
 Module[{t = [email protected]{[email protected], Range[[email protected], 1, -1]}},
  Switch[type,
   "standard", data/.Rul[email protected]@@First/@SplitBy[t, First],
   "modified", data/[email protected]@@Last/@SplitBy[t, First],
   "dense", data/.Thread[#->Range[[email protected]#]]&@SplitBy[t, First][[All, 1, 1]],
   "ordinal", [email protected][data],
   "fractional", data/[email protected]@@(Mean[#]/.{a_Rational:>N[a]}&)/@ SplitBy[t, First]]]

fmtRankedData[data_, type_] :=
 Labeled[Grid[
   SortBy[[email protected]{{[email protected]{rank[data[[All, 1]], type]},
       data}}, First], Alignment->Left], type<>" ranking:", Top]

[email protected]{fmtRankedData[data, #] & /@ {"standard", "modified", "dense",
    "ordinal", "fractional"}}


MODULE RankingMethods;
FROM FormatString IMPORT FormatString;
FROM RealStr IMPORT RealToFixed;
FROM Terminal IMPORT WriteString,WriteLn,ReadChar;

PROCEDURE WriteCard(c : CARDINAL);
VAR buf : ARRAY[0..15] OF CHAR;
BEGIN
    FormatString("%c", buf, c);
    WriteString(buf)
END WriteCard;

TYPE Entry = RECORD
    name : ARRAY[0..15] OF CHAR;
    score : CARDINAL;
END;

PROCEDURE OrdinalRanking(CONST entries : ARRAY OF Entry);
VAR
    buf : ARRAY[0..31] OF CHAR;
    i : CARDINAL;
BEGIN
    WriteString("Ordinal Ranking");
    WriteLn;
    WriteString("---------------");
    WriteLn;

    FOR i:=0 TO HIGH(entries) DO
        FormatString("%c\t%c\t%s\n", buf, i + 1, entries[i].score, entries[i].name);
        WriteString(buf)
    END;

    WriteLn
END OrdinalRanking;

PROCEDURE StandardRanking(CONST entries : ARRAY OF Entry);
VAR
    buf : ARRAY[0..31] OF CHAR;
    i,j : CARDINAL;
BEGIN
    WriteString("Standard Ranking");
    WriteLn;
    WriteString("---------------");
    WriteLn;

    j := 1;
    FOR i:=0 TO HIGH(entries) DO
        FormatString("%c\t%c\t%s\n", buf, j, entries[i].score, entries[i].name);
        WriteString(buf);
        IF entries[i+1].score < entries[i].score THEN
            j := i + 2
        END
    END;

    WriteLn
END StandardRanking;

PROCEDURE DenseRanking(CONST entries : ARRAY OF Entry);
VAR
    buf : ARRAY[0..31] OF CHAR;
    i,j : CARDINAL;
BEGIN
    WriteString("Dense Ranking");
    WriteLn;
    WriteString("---------------");
    WriteLn;

    j := 1;
    FOR i:=0 TO HIGH(entries) DO
        FormatString("%c\t%c\t%s\n", buf, j, entries[i].score, entries[i].name);
        WriteString(buf);
        IF entries[i+1].score < entries[i].score THEN
            INC(j)
        END
    END;

    WriteLn
END DenseRanking;

PROCEDURE ModifiedRanking(CONST entries : ARRAY OF Entry);
VAR
    buf : ARRAY[0..31] OF CHAR;
    i,j,count : CARDINAL;
BEGIN
    WriteString("Modified Ranking");
    WriteLn;
    WriteString("---------------");
    WriteLn;

    i := 0;
    j := 1;
    WHILE i < HIGH(entries) DO
        IF entries[i].score # entries[i+1].score THEN
            FormatString("%c\t%c\t%s\n", buf, i+1, entries[i].score, entries[i].name);
            WriteString(buf);

            count := 1;
            FOR j:=i+1 TO HIGH(entries)-1 DO
                IF entries[j].score # entries[j+1].score THEN
                    BREAK
                END;
                INC(count)
            END;

            j := 0;
            WHILE j < count-1 DO
                FormatString("%c\t%c\t%s\n", buf, i+count+1, entries[i+j+1].score, entries[i+j+1].name);
                WriteString(buf);
                INC(j)
            END;
            i := i + count - 1
        END;
        INC(i)
    END;

    FormatString("%c\t%c\t%s\n\n", buf, HIGH(entries)+1, entries[HIGH(entries)].score, entries[HIGH(entries)].name);
    WriteString(buf)
END ModifiedRanking;

PROCEDURE FractionalRanking(CONST entries : ARRAY OF Entry);
VAR
    buf : ARRAY[0..32] OF CHAR;
    i,j,count : CARDINAL;
    sum : REAL;
BEGIN
    WriteString("Fractional Ranking");
    WriteLn;
    WriteString("---------------");
    WriteLn;

    sum := 0.0;
    i := 0;
    WHILE i <= HIGH(entries) DO
        IF (i = HIGH(entries) - 1) OR (entries[i].score # entries[i+1].score) THEN
            RealToFixed(FLOAT(i+1),1,buf);
            WriteString(buf);
            FormatString("\t%c\t%s\n", buf, entries[i].score, entries[i].name);
            WriteString(buf)
        ELSE
            sum := FLOAT(i);
            count := 1;

            j := i;
            WHILE entries[j].score = entries[j+1].score DO
                sum := sum + FLOAT(j + 1);
                INC(count);
                INC(j)
            END;
            FOR j:=0 TO count-1 DO
                RealToFixed(sum/FLOAT(count)+1.0,1,buf);
                WriteString(buf);
                FormatString("\t%c\t%s\n", buf, entries[i+j].score, entries[i+j].name);
                WriteString(buf)
            END;
            i := i + count - 1
        END;
        INC(i)
    END
END FractionalRanking;

(* Main *)
TYPE EA = ARRAY[0..6] OF Entry;
VAR entries : EA;
BEGIN
    entries := EA{
        {"Solomon", 44},
        {"Jason", 42},
        {"Errol", 42},
        {"Garry", 41},
        {"Bernard", 41},
        {"Barry", 41},
        {"Stephen", 39}
    };

    OrdinalRanking(entries);
    StandardRanking(entries);
    DenseRanking(entries);
    ModifiedRanking(entries);
    FractionalRanking(entries);

    ReadChar
END RankingMethods.