function New-ThueMorse ( $Digits )
    {
    #  Start with seed 0
    $ThueMorse = "0"

    #  Decrement digits remaining
    $Digits--

    #  While we still have digits to calculate...
    While ( $Digits -gt 0 )
        {
        #  Number of digits we'll get this loop (what we still need up to the maximum available), corrected to 0 base
        $LastDigit = [math]::Min( $ThueMorse.Length, $Digits ) - 1

        #  Loop through each digit
        ForEach ( $i in 0..$LastDigit )
            {
            #  Append the twos complement
            $ThueMorse += ( 1 - $ThueMorse.Substring( $i, 1 ) )
            }

        #  Calculate the number of digits still remaining
        $Digits = $Digits - $LastDigit - 1
        }

    return $ThueMorse
    }

New-ThueMorse 5
New-ThueMorse 16
New-ThueMorse 73


EnableExplicit

Procedure.i count_bits(v.i)
  Define c.i
  While v
    c+v&1
    v>>1
  Wend
  ProcedureReturn c
EndProcedure

If OpenConsole()
  Define n.i
  For n=0 To 255
    Print(Str(count_bits(n)%2))
  Next
  PrintN(~"\n...fin") : Input()
EndIf


m='0'
print(m)
for i in range(0,6):
     m0=m
     m=m.replace('0','a')
     m=m.replace('1','0')
     m=m.replace('a','1')
     m=m0+m
     print(m)


const N=32, N2=(N * (N - 1) / 2), STEP=0.05;

fcn rho(xs,ys,rs, i,n){
   if (n < 0) return(0.0);
   if (not n) return(ys[i]);

   idx := (N - 1 - n) * (N - n) / 2 + i;
   if (Void==rs[idx])
      rs[idx] = (xs[i] - xs[i + n])
		/ (rho(xs, ys, rs, i, n - 1) - rho(xs, ys, rs, i + 1, n - 1))
		+ rho(xs, ys, rs, i + 1, n - 2);
   return(rs[idx]);
}

fcn thiele(xs,ys,rs, xin, n){
   if (n > N - 1) return(1.0);
   rho(xs, ys, rs, 0, n) - rho(xs, ys, rs, 0, n - 2)
      + (xin - xs[n]) / thiele(xs, ys, rs, xin, n + 1);
}

///////////

reg t_sin=L(), t_cos=L(), t_tan=L(),
    r_sin=L(), r_cos=L(), r_tan=L(),  xval=L();

i_sin := thiele.fpM("11101",t_sin, xval, r_sin, 0);
i_cos := thiele.fpM("11101",t_cos, xval, r_cos, 0);
i_tan := thiele.fpM("11101",t_tan, xval, r_tan, 0);

foreach i in (N){
   xval.append(x:=STEP*i);
   t_sin.append(x.sin());
   t_cos.append(x.cos());
   t_tan.append(t_sin[i] / t_cos[i]);
}
foreach i in (N2){ r_sin+Void; r_cos+Void; r_tan+Void; }

print("%16.14f\n".fmt( 6.0 * i_sin(0.5)));
print("%16.14f\n".fmt( 3.0 * i_cos(0.5)));
print("%16.14f\n".fmt( 4.0 * i_tan(1.0)));


[ [] 0 rot times
    [ i^ dup 1 - ^
      dup 1 >> ^ hex 55555555 & if
        [ 1 swap - ]
      dup dip
        [ digit join ] ] drop ]     is thue-morse ( n --> $ )

20 thue-morse echo$ cr


thue_morse <- function(steps) {
	sb1 <- "0"
	sb2 <- "1"
	for (idx in 1:steps) {
		tmp <- sb1
		sb1 <- paste0(sb1, sb2)
		sb2 <- paste0(sb2, tmp)
	}
	sb1
}
cat(thue_morse(6), "\n")


#lang racket
(define 1<->0 (match-lambda [#\0 #\1] [#\1 #\0]))
(define (thue-morse-step (s "0"))
  (string-append s (list->string (map 1<->0 (string->list s)))))

(define (thue-morse n)
  (let inr ((n (max (sub1 n) 0)) (rv (list "0")))
    (if (zero? n) (reverse rv) (inr (sub1 n) (cons (thue-morse-step (car rv)) rv)))))

(for-each displayln (thue-morse 7))


/*REXX pgm generates & displays the Thue─Morse sequence up to the Nth term (inclusive). */
parse arg N .                                    /*obtain the optional argument from CL.*/
if N=='' | N==","  then N= 80                    /*Not specified?  Then use the default.*/
$=                                               /*the Thue─Morse sequence  (so far).   */
         do j=0  to N                            /*generate sequence up to the Nth item.*/
         $= $ || $weight(j) // 2                 /*append the item to the Thue─Morse seq*/
         end   /*j*/
say $
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
$pop:    return  length( space( translate( arg(1), , 0), 0) )     /*count 1's in number.*/
$weight: return  $pop( x2b( d2x( arg(1) ) ) )                     /*dec──►bin, pop count*/


tm = "0"
see tm
for n = 1 to 6
    tm = thue_morse(tm)
    see tm
next

func thue_morse(previous)
     tm = ""
     for i = 1 to len(previous)
         if (substr(previous, i, 1) = "1") tm = tm + "0" else tm  = tm + "1" ok
     next
     see nl
     return (previous + tm)


const ITERATIONS: usize = 8;

fn neg(sequence: &String) -> String {
    sequence.chars()
        .map(|ch| {
            (1 - ch.to_digit(2).unwrap()).to_string()
        })
        .collect::<String>()
}

fn main() {
    let mut sequence: String = String::from("0");
    for i in 0..ITERATIONS {
        println!("{}: {}", i + 1, sequence);
        sequence = format!("{}{}", sequence, neg(&sequence));
    }
}


def thueMorse(n: Int): String = {
  val (sb0, sb1) = (new StringBuilder("0"), new StringBuilder("1"))
  (0 until n).foreach { _ =>
    val tmp = sb0.toString()
    sb0.append(sb1)
    sb1.append(tmp)
  }
  sb0.toString()
}

(0 to 6).foreach(i => println(s"$i : ${thueMorse(i)}"))


func recmap(repeat, seed, transform, callback) {
    func (repeat, seed) {
        callback(seed)
        repeat > 0 && __FUNC__(repeat-1, transform(seed))
    }(repeat, seed)
}

recmap(6, "0", {|s| s + s.tr('01', '10') }, { .say })


WITH recursive a(a) AS (SELECT '0' UNION ALL SELECT REPLACE(REPLACE(hex(a),'30','01'),'31','10') FROM a) SELECT * FROM a;


proc tm_expand {s} {string map {0 01 1 10} $s}
# this could also be written as:
# interp alias {} tm_expand {} string map {0 01 1 10}

proc tm {k} {
    set s 0
    while {[incr k -1] >= 0} {
        set s [tm_expand $s]
    }
    return $s
}


For x = 0 to 6                         ' sequence loop
  Print Using "_#";x;": ";             ' print sequence
  For y = 0 To (2^x)-1                 ' element loop
    Print AND(FUNC(_Parity(y)),1);     ' print element
  Next                                 ' next element
  Print                                ' terminate elements line
Next                                   ' next sequence

End

_Parity Param (1)                      ' parity function
  Local (1)                            ' number of bits set
  [email protected] = 0                               ' no bits set yet
  Do While [email protected] # 0                      ' until all bits are counted
    If AND ([email protected], 1) Then [email protected] = [email protected] + 1    ' bit set? increment count
    [email protected] = SHL([email protected], -1)                   ' shift the number
  Loop
Return ([email protected])                            ' return number of bits set


Option Explicit

Sub Main()
Dim i&, t$
    For i = 1 To 8
        t = Thue_Morse(t)
        Debug.Print i & ":=> " & t
    Next
End Sub

Private Function Thue_Morse(s As String) As String
Dim k$
    If s = "" Then
        k = "0"
    Else
        k = s
        k = Replace(k, "1", "2")
        k = Replace(k, "0", "1")
        k = Replace(k, "2", "0")
    End If
    Thue_Morse = s & k
End Function


Imports System.Text

Module Module1

    Sub Sequence(steps As Integer)
        Dim sb1 As New StringBuilder("0")
        Dim sb2 As New StringBuilder("1")
        For index = 1 To steps
            Dim tmp = sb1.ToString
            sb1.Append(sb2)
            sb2.Append(tmp)
        Next
        Console.WriteLine(sb1)
    End Sub

    Sub Main()
        Sequence(6)
    End Sub

End Module


var thueMorse = Fn.new { |n|
    var sb0 = "0"
    var sb1 = "1"
    (0...n).each { |i|
        var tmp = sb0
        sb0 = sb0 + sb1
        sb1 = sb1 + tmp
    }
    return sb0
}

for (i in 0..6) System.print("%(i) : %(thueMorse.call(i))")


(defun thue-morse (n)
    (defun flip-bits (s)
        (defun flip (l)
            (if (not (null l))
                (cons
                    (if (equal (car l) #\1)
                        #\0
                        #\1)
                    (flip (cdr l)))))
        (list->string (flip (string->list s))))
    (if (= n 0)
        "0"
        (string-append (thue-morse (- n 1)) (flip-bits (thue-morse (- n 1))))))

; define RANGE, for testing purposes

(defun range (x y)
    (if (< x y)
        (cons x (range (+ x 1) y))))

; test THUE-MORSE by printing the strings it returns for n = 0 to n = 6

(mapcar (lambda (n) (print (thue-morse n))) (range 0 7))


string 0;               \use zero-terminated strings
char Thue;
int  N, I, J;
[Thue:= Reserve(Free);  \reserve all available memory
Thue(0):= ^0;
J:= 1;                  \set index to terminator
for N:= 0 to 6 do
        [Thue(J):= 0;   \terminate string
        Text(0, Thue);  \show result
        CrLf(0);
        I:= 0;          \invert string and store it on the end
        repeat  Thue(J+I):= Thue(I) xor 1;
                I:= I+1;
        until   I = J;
        J:= J+I;        \set index to terminator
        ];
]


tm$ = "0"
for i=1 to 8
    ? tm$
    tm$ = tm$ + inverte$(tm$)
next

sub inverte$(tm$)
    local i

    for i = 1 to len(tm$)
        mid$(tm$, i, 1) = str$(not val(mid$(tm$, i, 1)))
    next
    return tm$
end sub


V data = [(‘Tyler Bennett’, ‘E10297’, 32000, ‘D101’),
          (‘John Rappl’, ‘E21437’, 47000, ‘D050’),
          (‘George Woltman’, ‘E00127’, 53500, ‘D101’),
          (‘Adam Smith’, ‘E63535’, 18000, ‘D202’),
          (‘Claire Buckman’, ‘E39876’, 27800, ‘D202’),
          (‘David McClellan’, ‘E04242’, 41500, ‘D101’),
          (‘Rich Holcomb’, ‘E01234’, 49500, ‘D202’),
          (‘Nathan Adams’, ‘E41298’, 21900, ‘D050’),
          (‘Richard Potter’, ‘E43128’, 15900, ‘D101’),
          (‘David Motsinger’, ‘E27002’, 19250, ‘D202’),
          (‘Tim Sampair’, ‘E03033’, 27000, ‘D101’),
          (‘Kim Arlich’, ‘E10001’, 57000, ‘D190’),
          (‘Timothy Grove’, ‘E16398’, 29900, ‘D190’)]

DefaultDict[String, [(String, String, Int, String)]] departments
L(rec) data
   departments[rec[3]].append(rec)

V n = 3
L(department, recs) sorted(departments.items())
   print(‘Department #.’.format(department))
   print(‘ #<15  #<15  #<15  #<15 ’.format(‘Employee Name’, ‘Employee ID’, ‘Salary’, ‘Department’))
   L(rec) sorted(recs, key' rec -> rec[2], reverse' 1B)[0 .< n]
      print(‘ #<15  #<15  #<15  #<15 ’.format(rec[0], rec[1], rec[2], rec[3]))
   print()


DEFINE PTR="CARD"
DEFINE ENTRY_SIZE="8"

TYPE Employee=[
  PTR name,id,dep ;CHAR ARRAY
  CARD salary]

BYTE ARRAY data(200)
BYTE count=[0]

PTR FUNC GetItemAddr(INT index)
  PTR addr

  addr=data+index*ENTRY_SIZE
RETURN (addr)

PROC Append(CHAR ARRAY n,i CARD s CHAR ARRAY d)
  Employee POINTER dst

  dst=GetItemAddr(count)
  dst.name=n
  dst.id=i
  dst.dep=d
  dst.salary=s
  count==+1
RETURN

PROC InitData()
  Append("Tyler Bennett","E10297",32000,"D101")
  Append("John Rappl","E21437",47000,"D050")
  Append("George Woltman","E00127",53500,"D101")
  Append("Adam Smith","E63535",18000,"D202")
  Append("Claire Buckman","E39876",27800,"D202")
  Append("David McClellan","E04242",41500,"D101")
  Append("Rich Holcomb","E01234",49500,"D202")
  Append("Nathan Adams","E41298",21900,"D050")
  Append("Richard Potter","E43128",15900,"D101")
  Append("David Motsinger","E27002",19250,"D202")
  Append("Tim Sampair","E03033",27000,"D101")
  Append("Kim Arlich","E10001",57000,"D190")
  Append("Timothy Grove","E16398",29900,"D190")
RETURN

PROC Swap(Employee POINTER e1,e2)
  PTR tmp

  tmp=e1.name e1.name=e2.name e2.name=tmp
  tmp=e1.id e1.id=e2.id e2.id=tmp
  tmp=e1.dep e1.dep=e2.dep e2.dep=tmp
  tmp=e1.salary e1.salary=e2.salary e2.salary=tmp
RETURN

PROC Sort()
  INT i,j,minpos,comp
  Employee POINTER e1,e2

  FOR i=0 TO count-2
  DO
    minpos=i
    FOR j=i+1 TO count-1
    DO
      e1=GetItemAddr(minpos)
      e2=GetItemAddr(j)
      comp=SCompare(e1.dep,e2.dep)
      IF comp>0 OR comp=0 AND e1.salary<e2.salary THEN
        minpos=j
      FI
    OD

    IF minpos#i THEN
      e1=GetItemAddr(minpos)
      e2=GetItemAddr(i)
      Swap(e1,e2)
    FI
  OD
RETURN

PROC TopRank(BYTE n)
  BYTE i,c
  CHAR ARRAY d
  Employee POINTER e

  i=0
  WHILE i<count
  DO
    e=GetItemAddr(i)
    IF i=0 OR SCompare(e.dep,d)#0 THEN
      d=e.dep c=0
      IF i>0 THEN PutE() FI
      PrintF("Department %S:%E",d)
      c==+1
      PrintF("  %U %S %S%E",e.salary,e.id,e.name)
    ELSEIF c<n THEN
      c==+1
      PrintF("  %U %S %S%E",e.salary,e.id,e.name)
    FI
    i==+1
  OD
RETURN

PROC Main()
  InitData()
  Sort()
  TopRank(3)
RETURN


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

procedure Top is
   type Departments is (D050, D101, D190, D202);
   type Employee_Data is record
      Name       : String (1 .. 15);
      ID         : String (1 .. 6);
      Salary     : Positive;
      Department : Departments;
   end record;

   package Employee_Vectors is new Ada.Containers.Vectors
     (Element_Type => Employee_Data, Index_Type => Positive);

   function Compare_Salary (Left, Right : Employee_Data) return Boolean is
   begin
      return Left.Salary > Right.Salary;
   end Compare_Salary;
   package Salary_Sort is new Employee_Vectors.Generic_Sorting
     ("<" => Compare_Salary);

   function Compare_Department (Left, Right : Employee_Data) return Boolean is
   begin
      return Left.Department < Right.Department;
   end Compare_Department;
   package Department_Sort is new Employee_Vectors.Generic_Sorting
     ("<" => Compare_Department);

   Example_Data : Employee_Vectors.Vector;
begin
   -- fill data
   Example_Data.Append (("Tyler Bennett  ", "E10297", 32000, D101));
   Example_Data.Append (("John Rappl     ", "E21437", 47000, D050));
   Example_Data.Append (("George Woltman ", "E00127", 53500, D101));
   Example_Data.Append (("Adam Smith     ", "E63535", 18000, D202));
   Example_Data.Append (("Claire Buckman ", "E39876", 27800, D202));
   Example_Data.Append (("David McClellan", "E04242", 41500, D101));
   Example_Data.Append (("Rich Holcomb   ", "E01234", 49500, D202));
   Example_Data.Append (("Nathan Adams   ", "E41298", 21900, D050));
   Example_Data.Append (("Richard Potter ", "E43128", 15900, D101));
   Example_Data.Append (("David Motsinger", "E27002", 19250, D202));
   Example_Data.Append (("Tim Sampair    ", "E03033", 27000, D101));
   Example_Data.Append (("Kim Arlich     ", "E10001", 57000, D190));
   Example_Data.Append (("Timothy Grove  ", "E16398", 29900, D190));
   -- sort by salary
   Salary_Sort.Sort (Example_Data);
   -- output each department
   for Department in Departments loop
      declare
         Position : Employee_Vectors.Cursor := Example_Data.First;
         Employee : Employee_Data;
      begin
         Ada.Text_IO.Put_Line ("Department " & Departments'Image (Department));
         for I in 1 .. 3 loop
            Employee := Employee_Vectors.Element (Position);
            while Employee.Department /= Department loop
               Position := Employee_Vectors.Next (Position);
               Employee := Employee_Vectors.Element (Position);
            end loop;
            Ada.Text_IO.Put_Line ("   " & Employee.Name & " | " &
                                  Employee.ID & " | " &
                                  Positive'Image (Employee.Salary));
            Position := Employee_Vectors.Next (Position);
         end loop;
      exception
         when Constraint_Error =>
            null;
      end;
   end loop;
end Top;


Add_Employee(record employees, text name, id, integer salary, text department)
{
    employees[name] = list(name, id, salary, department);
}

collect(record top, employees)
{
    for (, list l in employees) {
        top.v_index(l[3]).v_list(l[2]).link(-1, l);
    }
    for (text department, index x in top) {
        list t;

        x.ucall(l_ucall, 0, l_append, 1, t);
        if (N < ~t.reverse) {
            t.erase(N, -1);
        }
        top[department] = t;
    }
}

print_department(text department, list employees)
{
    o_("Department ", department, "\n");

    for (, list l in employees) {
        o_form("  ~ | ~ | ~\n", l[0], l[1], l[2]);
    }
}

main(void)
{
    record employees, top;

    Add_Employee(employees, "Tyler Bennett  ", "E10297", 32000, "D101");
    Add_Employee(employees, "John Rappl     ", "E21437", 47000, "D050");
    Add_Employee(employees, "George Woltman ", "E00127", 53500, "D101");
    Add_Employee(employees, "Adam Smith     ", "E63535", 18000, "D202");
    Add_Employee(employees, "Claire Buckman ", "E39876", 27800, "D202");
    Add_Employee(employees, "David McClellan", "E04242", 41500, "D101");
    Add_Employee(employees, "Rich Holcomb   ", "E01234", 49500, "D202");
    Add_Employee(employees, "Nathan Adams   ", "E41298", 21900, "D050");
    Add_Employee(employees, "Richard Potter ", "E43128", 15900, "D101");
    Add_Employee(employees, "David Motsinger", "E27002", 19250, "D202");
    Add_Employee(employees, "Tim Sampair    ", "E03033", 27000, "D101");
    Add_Employee(employees, "Kim Arlich     ", "E10001", 57000, "D190");
    Add_Employee(employees, "Timothy Grove  ", "E16398", 29900, "D190");

    collect(top, employees);

    top.wcall(print_department, 0, 1);

    0;
}


use AppleScript version "2.3.1" -- Mac OS X 10.9 (Mavericks) or later for these 'use' commands!
use sorter : script "Custom Iterative Ternary Merge Sort" -- <https://macscripter.net/viewtopic.php?pid=194430#p194430>

on topNSalariesPerDepartment(employeeRecords, n)
    set output to {}
    set employeeCount to (count employeeRecords)
    if ((employeeCount > 0) and (n > 0)) then
        -- Sort a copy of the employee record list by department with descending subsorts on salary.
        copy employeeRecords to employeeRecords
        script comparer
            on isGreater(a, b)
                return ((a's department > b's department) or ((a's department = b's department) and (a's salary < b's salary)))
            end isGreater
        end script
        considering numeric strings
            tell sorter to sort(employeeRecords, 1, employeeCount, {comparer:comparer})
        end considering

        -- Initialise the output with data from the first record in the sorted list, then work through the rest of the list.
        set {department:previousDepartment, salary:previousSalary} to beginning of employeeRecords
        set {padValue, topSalaries, counter} to {missing value, {previousSalary}, 1}
        set end of output to {department:previousDepartment, salaries:topSalaries}
        repeat with i from 2 to employeeCount
            set {department:thisDepartment, salary:thisSalary} to item i of employeeRecords
            if (thisDepartment is previousDepartment) then
                -- Another record from the same department. Include its salary in the output if different from
                -- the previous one's and if fewer than n salaries from the department have been included so far.
                if ((thisSalary < previousSalary) and (counter < n)) then
                    set end of topSalaries to thisSalary
                    set counter to counter + 1
                    set previousSalary to thisSalary
                end if
            else
                -- First record of the next department.
                -- Pad the previous department's salary list with missing values if it has fewer than n entries.
                repeat (n - counter) times
                    set end of topSalaries to padValue
                end repeat
                -- Start a result record for the new department and add it to the output.
                set topSalaries to {thisSalary}
                set counter to 1
                set end of output to {department:thisDepartment, salaries:topSalaries}
                set previousDepartment to thisDepartment
                set previousSalary to thisSalary
            end if
        end repeat
        -- Pad the last department's salary list if necessary.
        repeat (n - counter) times
            set end of topSalaries to padValue
        end repeat
    end if

    return output
end topNSalariesPerDepartment

on demo()
    set employeeRecords to {¬
        {|name|:"Tyler Bennett", |ID|:"E10297", salary:32000, department:"D101"}, ¬
        {|name|:"John Rappl", |ID|:"E21437", salary:47000, department:"D050"}, ¬
        {|name|:"George Woltman", |ID|:"E00127", salary:53500, department:"D101"}, ¬
        {|name|:"Adam Smith", |ID|:"E63535", salary:18000, department:"D202"}, ¬
        {|name|:"Claire Buckman", |ID|:"E39876", salary:27800, department:"D202"}, ¬
        {|name|:"David McClellan", |ID|:"E04242", salary:41500, department:"D101"}, ¬
        {|name|:"Rich Holcomb", |ID|:"E01234", salary:49500, department:"D202"}, ¬
        {|name|:"Nathan Adams", |ID|:"E41298", salary:21900, department:"D050"}, ¬
        {|name|:"Richard Potter", |ID|:"E43128", salary:15900, department:"D101"}, ¬
        {|name|:"David Motsinger", |ID|:"E27002", salary:19250, department:"D202"}, ¬
        {|name|:"Tim Sampair", |ID|:"E03033", salary:27000, department:"D101"}, ¬
        {|name|:"Kim Arlich", |ID|:"E10001", salary:57000, department:"D190"}, ¬
        {|name|:"Timothy Grove", |ID|:"E16398", salary:29900, department:"D190"}, ¬
        {|name|:"Simila Pey", |ID|:"E16399", salary:29900, department:"D190"} ¬
            }
    set n to 4
    set topSalaryRecords to topNSalariesPerDepartment(employeeRecords, n)
    --> eg. {{department:"D050", salaries:{47000, 21900, missing value, missing value}}, … }

    -- Derive a text report from the result.
    set report to {"Top " & n & " salaries per department:"}
    set astid to AppleScript's text item delimiters
    set AppleScript's text item delimiters to "  "
    repeat with thisRecord in topSalaryRecords
        set i to n
        repeat while (item i of thisRecord's salaries is missing value)
            set item i of thisRecord's salaries to "-"
            set i to i - 1
        end repeat
        set end of report to thisRecord's department & ":    " & thisRecord's salaries
    end repeat
    set AppleScript's text item delimiters to linefeed
    set report to report as text
    set AppleScript's text item delimiters to astid
    return report
end demo

demo()


printTopEmployees: function [count, entries][
    data: read.csv.withHeaders entries
    departments: sort unique map data 'row -> row\Department
    loop departments 'd [
        print "----------------------"
        print ["department:" d]
        print "----------------------"
        loop first.n: count
            sort.descending.by:"Salary"
                select data 'row [row\Department = d] 'employee ->
                    print [get employee "Employee Name" "->" employee\Salary]
        print ""
    ]
]

printTopEmployees 2 {
    Employee Name,Employee ID,Salary,Department
    Tyler Bennett,E10297,32000,D101
    John Rappl,E21437,47000,D050
    George Woltman,E00127,53500,D101
    Adam Smith,E63535,18000,D202
    Claire Buckman,E39876,27800,D202
    David McClellan,E04242,41500,D101
    Rich Holcomb,E01234,49500,D202
    Nathan Adams,E41298,21900,D050
    Richard Potter,E43128,15900,D101
    David Motsinger,E27002,19250,D202
    Tim Sampair,E03033,27000,D101
    Kim Arlich,E10001,57000,D190
    Timothy Grove,E16398,29900,D190
}


Departments = D050, D101, D190, D202
StringSplit, Department_, Departments, `,, %A_Space%

; Employee Name, Employee ID, Salary, Department
Add_Employee("Tyler Bennett  ", "E10297", 32000, "D101")
Add_Employee("John Rappl     ", "E21437", 47000, "D050")
Add_Employee("George Woltman ", "E00127", 53500, "D101")
Add_Employee("Adam Smith     ", "E63535", 18000, "D202")
Add_Employee("Claire Buckman ", "E39876", 27800, "D202")
Add_Employee("David McClellan", "E04242", 41500, "D101")
Add_Employee("Rich Holcomb   ", "E01234", 49500, "D202")
Add_Employee("Nathan Adams   ", "E41298", 21900, "D050")
Add_Employee("Richard Potter ", "E43128", 15900, "D101")
Add_Employee("David Motsinger", "E27002", 19250, "D202")
Add_Employee("Tim Sampair    ", "E03033", 27000, "D101")
Add_Employee("Kim Arlich     ", "E10001", 57000, "D190")
Add_Employee("Timothy Grove  ", "E16398", 29900, "D190")

; display top 3 ranks for each department
Loop, %Department_0% ; all departments
    MsgBox,, % "Department:  " Department_%A_Index%
           , % TopRank(3, Department_%A_Index%)

;---------------------------------------------------------------------------
TopRank(N, Department) { ; find the top N salaries in each department
;---------------------------------------------------------------------------
    local Collection := Msg := ""
    Loop, %m% ; all employees
        If (Employee_%A_Index%_Dept = Department)
            ; collect all the salaries being paid in this department
            Collection .= (Collection ? "," : "") Employee_%A_Index%_Salary
    Sort, Collection, ND,R
    StringSplit, Collection, Collection, `,
    Loop, % (N < Collection0) ? N : Collection0 {
        Salary := Collection%A_Index%
        Loop, %m% ; find the respective employee
            If (Employee_%A_Index%_Salary = Salary)
                ; and put out his/her details
                Msg .= Employee_%A_Index%_Name "`t"
                    .  Employee_%A_Index%_ID "`t"
                    .  Employee_%A_Index%_Salary "`t"
                    .  Employee_%A_Index%_Dept "`t`n"
    }
    Return, Msg
}

;---------------------------------------------------------------------------
Add_Employee(Name, ID, Salary, Department) {
;---------------------------------------------------------------------------
    global
    m++
    Employee_%m%_Name   := Name
    Employee_%m%_ID     := ID
    Employee_%m%_Salary := Salary
    Employee_%m%_Dept   := Department
}


# syntax: GAWK -f TOP_RANK_PER_GROUP.AWK [n]
#
# sorting:
#   PROCINFO["sorted_in"] is used by GAWK
#   SORTTYPE is used by Thompson Automation's TAWK
#
BEGIN {
    arrA[++n] = "Employee Name,Employee ID,Salary,Department" # raw data
    arrA[++n] = "Tyler Bennett,E10297,32000,D101"
    arrA[++n] = "John Rappl,E21437,47000,D050"
    arrA[++n] = "George Woltman,E00127,53500,D101"
    arrA[++n] = "Adam Smith,E63535,18000,D202"
    arrA[++n] = "Claire Buckman,E39876,27800,D202"
    arrA[++n] = "David McClellan,E04242,41500,D101"
    arrA[++n] = "Rich Holcomb,E01234,49500,D202"
    arrA[++n] = "Nathan Adams,E41298,21900,D050"
    arrA[++n] = "Richard Potter,E43128,15900,D101"
    arrA[++n] = "David Motsinger,E27002,19250,D202"
    arrA[++n] = "Tim Sampair,E03033,27000,D101"
    arrA[++n] = "Kim Arlich,E10001,57000,D190"
    arrA[++n] = "Timothy Grove,E16398,29900,D190"
    for (i=2; i<=n; i++) { # build internal structure
      split(arrA[i],arrB,",")
      arrC[arrB[4]][arrB[3]][arrB[2] " " arrB[1]] # I.E. arrC[dept][salary][id " " name]
    }
    show = (ARGV[1] == "") ? 1 : ARGV[1] # employees to show per department
    printf("DEPT SALARY EMPID  NAME\n\n") # produce report
    PROCINFO["sorted_in"] = "@ind_str_asc" ; SORTTYPE = 1
    for (i in arrC) {
      PROCINFO["sorted_in"] = "@ind_str_desc" ; SORTTYPE = 9
      shown = 0
      for (j in arrC[i]) {
        PROCINFO["sorted_in"] = "@ind_str_asc" ; SORTTYPE = 1
        for (k in arrC[i][j]) {
          if (shown++ < show) {
            printf("%-4s %6s %s\n",i,j,k)
            printed++
          }
        }
      }
      if (printed > 0) { print("") }
      printed = 0
    }
    exit(0)
}


      (Tyler Bennett,E10297,32000,D101)
      (John Rappl,E21437,47000,D050)
      (George Woltman,E00127,53500,D101)
      (Adam Smith,E63535,18000,D202)
      (Claire Buckman,E39876,27800,D202)
      (David McClellan,E04242,41500,D101)
      (Rich Holcomb,E01234,49500,D202)
      (Nathan Adams,E41298,21900,D050)
      (Richard Potter,E43128,15900,D101)
      (David Motsinger,E27002,19250,D202)
      (Tim Sampair,E03033,27000,D101)
      (Kim Arlich,E10001,57000,D190)
      (Timothy Grove,E16398,29900,D190)
  : ?employees
& ( toprank
  =   employees N n P "Employee Name" "Employee ID" SalaryDepartment
    .   !arg:(?employees.?N)
      & 1:?P
      &   whl
        ' (   !employees
            :   (?"Employee Name",?"Employee ID",?Salary,?Department)
                ?employees
          & !Department^(!Salary.!"Employee Name".!"Employee ID")*!P:?P
          )
      & out$(Top !N "salaries per department.")
      &   whl
        ' ( !P:%?Department^?employees*?P
          & out$(str$("Department " !Department ":"))
          & !N:?n
          &   whl
            ' ( !n+-1:~<0:?n
              &   !employees
                : ?employees+(?Salary.?"Employee Name".?"Employee ID")
              &   out
                $ (str$("  " !"Employee Name" " (" !"Employee ID" "):" !Salary))
              )
          )
  )
& toprank$(!employees.3)
& ;


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

typedef struct {
    const char *name, *id, *dept;
    int sal;
} person;

person ppl[] = {
    {"Tyler Bennett",   "E10297", "D101", 32000},
    {"John Rappl",      "E21437", "D050", 47000},
    {"George Woltman",  "E00127", "D101", 53500},
    {"Adam Smith",      "E63535", "D202", 18000},
    {"Claire Buckman",  "E39876", "D202", 27800},
    {"David McClellan", "E04242", "D101", 41500},
    {"Rich Holcomb",    "E01234", "D202", 49500},
    {"Nathan Adams",    "E41298", "D050", 21900},
    {"Richard Potter",  "E43128", "D101", 15900},
    {"David Motsinger", "E27002", "D202", 19250},
    {"Tim Sampair",     "E03033", "D101", 27000},
    {"Kim Arlich",      "E10001", "D190", 57000},
    {"Timothy Grove",   "E16398", "D190", 29900},
};

int pcmp(const void *a, const void *b)
{
    const person *aa = a, *bb = b;
    int x = strcmp(aa->dept, bb->dept);
    if (x) return x;
    return aa->sal > bb->sal ? -1 : aa->sal < bb->sal;
}

#define N sizeof(ppl)/sizeof(person)
void top(int n)
{
    int i, rank;
    qsort(ppl, N, sizeof(person), pcmp);

    for (i = rank = 0; i < N; i++) {
        if (i && strcmp(ppl[i].dept, ppl[i - 1].dept)) {
            rank = 0;
            printf("\n");
        }

        if (rank++ < n)
            printf("%s %d: %s\n", ppl[i].dept, ppl[i].sal, ppl[i].name);
    }
}

int main()
{
    top(2);
    return 0;
}


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

public class Program
{
    class Employee
    {
        public Employee(string name, string id, int salary, string department)
        {
            Name = name;
            Id = id;
            Salary = salary;
            Department = department;
        }

        public string Name { get; private set; }
        public string Id { get; private set; }
        public int Salary { get; private set; }
        public string Department { get; private set; }

        public override string ToString()
        {
            return String.Format("{0, -25}\t{1}\t{2}", Name, Id, Salary);
        }
    }

    private static void Main(string[] args)
    {
        var employees = new List<Employee>
                        {
                            new Employee("Tyler Bennett", "E10297", 32000, "D101"),
                            new Employee("John Rappl", "E21437", 47000, "D050"),
                            new Employee("George Woltman", "E21437", 53500, "D101"),
                            new Employee("Adam Smith", "E21437", 18000, "D202"),
                            new Employee("Claire Buckman", "E39876", 27800, "D202"),
                            new Employee("David McClellan", "E04242", 41500, "D101"),
                            new Employee("Rich Holcomb", "E01234", 49500, "D202"),
                            new Employee("Nathan Adams", "E41298", 21900, "D050"),
                            new Employee("Richard Potter", "E43128", 15900, "D101"),
                            new Employee("David Motsinger", "E27002", 19250, "D202"),
                            new Employee("Tim Sampair", "E03033", 27000, "D101"),
                            new Employee("Kim Arlich", "E10001", 57000, "D190"),
                            new Employee("Timothy Grove", "E16398", 29900, "D190")
                        };

        DisplayTopNPerDepartment(employees, 2);
    }

    static void DisplayTopNPerDepartment(IEnumerable<Employee> employees, int n)
    {
        var topSalariesByDepartment =
            from employee in employees
            group employee by employee.Department
            into g
            select new
                    {
                        Department = g.Key,
                        TopEmployeesBySalary = g.OrderByDescending(e => e.Salary).Take(n)
                    };

        foreach (var x in topSalariesByDepartment)
        {
            Console.WriteLine("Department: " + x.Department);
            foreach (var employee in x.TopEmployeesBySalary)
                Console.WriteLine(employee);
            Console.WriteLine("----------------------------");
        }
    }
}


#include <string>
#include <set>
#include <list>
#include <map>
#include <iostream>

struct Employee
{
    std::string Name;
    std::string ID;
    unsigned long Salary;
    std::string Department;
    Employee(std::string _Name = "", std::string _ID = "", unsigned long _Salary = 0, std::string _Department = "")
    : Name(_Name), ID(_ID), Salary(_Salary), Department(_Department)
    { }

    void display(std::ostream& out) const
    {
        out << Name << "\t" << ID << "\t" << Salary << "\t" << Department << std::endl;
    }
};

// We'll tell std::set to use this to sort our employees.
struct CompareEarners
{
    bool operator()(const Employee& e1, const Employee& e2)
    {
        return (e1.Salary > e2.Salary);
    }
};

// A few typedefs to make the code easier to type, read and maintain.
typedef std::list<Employee> EMPLOYEELIST;

// Notice the CompareEarners; We're telling std::set to user our specified comparison mechanism
// to sort its contents.
typedef std::set<Employee, CompareEarners> DEPARTMENTPAYROLL;

typedef std::map<std::string, DEPARTMENTPAYROLL> DEPARTMENTLIST;

void initialize(EMPLOYEELIST& Employees)
{
    // Initialize our employee list data source.
    Employees.push_back(Employee("Tyler Bennett", "E10297", 32000, "D101"));
    Employees.push_back(Employee("John Rappl", "E21437", 47000, "D050"));
    Employees.push_back(Employee("George Woltman", "E21437", 53500, "D101"));
    Employees.push_back(Employee("Adam Smith", "E21437", 18000, "D202"));
    Employees.push_back(Employee("Claire Buckman", "E39876", 27800, "D202"));
    Employees.push_back(Employee("David McClellan", "E04242", 41500, "D101"));
    Employees.push_back(Employee("Rich Holcomb", "E01234", 49500, "D202"));
    Employees.push_back(Employee("Nathan Adams", "E41298", 21900, "D050"));
    Employees.push_back(Employee("Richard Potter", "E43128", 15900, "D101"));
    Employees.push_back(Employee("David Motsinger", "E27002", 19250, "D202"));
    Employees.push_back(Employee("Tim Sampair", "E03033", 27000, "D101"));
    Employees.push_back(Employee("Kim Arlich", "E10001", 57000, "D190"));
    Employees.push_back(Employee("Timothy Grove", "E16398", 29900, "D190"));
}

void group(EMPLOYEELIST& Employees, DEPARTMENTLIST& Departments)
{
    // Loop through all of our employees.
    for( EMPLOYEELIST::iterator iEmployee = Employees.begin();
         Employees.end() != iEmployee;
         ++iEmployee )
    {
        DEPARTMENTPAYROLL& groupSet = Departments[iEmployee->Department];

        // Add our employee to this group.
        groupSet.insert(*iEmployee);
    }
}

void present(DEPARTMENTLIST& Departments, unsigned int N)
{
    // Loop through all of our departments
    for( DEPARTMENTLIST::iterator iDepartment = Departments.begin();
         Departments.end() != iDepartment;
         ++iDepartment )
    {
        std::cout << "In department " << iDepartment->first << std::endl;
        std::cout << "Name\t\tID\tSalary\tDepartment" << std::endl;
        // Get the top three employees for each employee
        unsigned int rank = 1;
        for( DEPARTMENTPAYROLL::iterator iEmployee = iDepartment->second.begin();
             ( iDepartment->second.end() != iEmployee) && (rank <= N);
             ++iEmployee, ++rank )
        {
            iEmployee->display(std::cout);
        }
        std::cout << std::endl;
    }
}

int main(int argc, char* argv[])
{
    // Our container for our list of employees.
    EMPLOYEELIST Employees;

    // Fill our list of employees
    initialize(Employees);

    // Our departments.
    DEPARTMENTLIST Departments;

    // Sort our employees into their departments.
    // This will also rank them.
    group(Employees, Departments);

    // Display the top 3 earners in each department.
    present(Departments, 3);

    return 0;
}


class Employee(name, id, salary, dept) {
    shared String name;
    shared String id;
    shared Integer salary;
    shared String dept;

    string => "``name`` ``id`` $``salary``.00 ``dept``";
}

Employee[] employees = [
    Employee("Tyler Bennett", "E10297", 32000, "D101"),
    Employee("John Rappl", "E21437", 47000, "D050"),
    Employee("George Woltman", "E00127", 53500, "D101"),
    Employee("Adam Smith", "E63535", 18000, "D202"),
    Employee("Claire Buckman", "E39876", 27800, "D202"),
    Employee("David McClellan", "E04242", 41500, "D101"),
    Employee("Rich Holcomb", "E01234", 49500, "D202"),
    Employee("Nathan Adams", "E41298", 21900, "D050"),
    Employee("Richard Potter", "E43128", 15900, "D101"),
    Employee("David Motsinger", "E27002", 19250, "D202"),
    Employee("Tim Sampair", "E03033", 27000, "D101"),
    Employee("Kim Arlich", "E10001", 57000, "D190"),
    Employee("Timothy Grove", "E16398", 29900, "D190")
];

"This is the main function."
shared void run() {

    value topRanked = topSalaries(employees, 3);

    for (dept -> staff in topRanked) {
        print(dept);
        for (employee in staff) {
            print("\t``employee``");
        }
    }
}

Map<String, {Employee*}> topSalaries({Employee*} employees, Integer n) => map {
    for (dept -> staff in employees.group(Employee.dept))
    dept -> staff.sort(byDecreasing(Employee.salary)).take(n)
};


(use '[clojure.contrib.seq-utils :only (group-by)])

(defstruct employee :Name :ID :Salary :Department)

(def data
     (->> '(("Tyler Bennett" E10297 32000 D101)
            ("John Rappl" E21437 47000 D050)
            ("George Woltman" E00127 53500 D101)
            ("Adam Smith" E63535 18000 D202)
            ("Claire Buckman" E39876 27800 D202)
            ("David McClellan" E04242 41500 D101)
            ("Rich Holcomb" E01234 49500 D202)
            ("Nathan Adams" E41298 21900 D050)
            ("Richard Potter" E43128 15900 D101)
            ("David Motsinger" E27002 19250 D202)
            ("Tim Sampair" E03033 27000 D101)
            ("Kim Arlich" E10001 57000 D190)
            ("Timothy Grove" E16398 29900 D190))
          (map #(apply (partial struct employee) %))))

(doseq [[dep emps] (group-by :Department data)]
  (println "Department:" dep)
  (doseq [e (take 3 (reverse (sort-by :Salary emps)))]
    (println e)))


(defun top-n-by-group (n data value-key group-key predicate &key (group-test 'eql))
  (let ((not-pred (complement predicate))
        (group-data (make-hash-table :test group-test)))
    (labels ((value (datum)
               (funcall value-key datum))
             (insert (x list)
               (merge 'list (list x) list not-pred :key #'value))
             (entry (group)
               "Return the entry for the group, creating it if
                necessary. An entry is a list whose first element is
                k, the number of items currently associated with the
                group (out of n total), and whose second element is
                the list of the k current top items for the group."
               (multiple-value-bind (entry presentp)
                   (gethash group group-data)
                 (if presentp entry
                   (setf (gethash group group-data)
                         (list 0 '())))))
             (update-entry (entry datum)
               "Update the entry using datum. If there are already n
                items associated with the entry, then when datum's value
                is greater than the current least item, data is merged into
                the items, and the list (minus the first element) is
                stored in entry. Otherwise, if there are fewer than n
                items in the entry, datum is merged in, and the
                entry's k is increased by 1."
               (if (= n (first entry))
                 (when (funcall predicate (value datum) (value (first (second entry))))
                   (setf (second entry)
                         (cdr (insert datum (second entry)))))
                 (setf (first entry) (1+ (first entry))
                       (second entry) (insert datum (second entry))))))
      (dolist (datum data group-data)
        (update-entry (entry (funcall group-key datum)) datum)))))


import std.stdio, std.algorithm, std.conv, std.range;

struct Employee {
  string name, id;
  uint salary;
  string department;
}

immutable Employee[] data = [
    {"Tyler Bennett",   "E10297", 32_000, "D101"},
    {"John Rappl",      "E21437", 47_000, "D050"},
    {"George Woltman",  "E00127", 53_500, "D101"},
    {"Adam Smith",      "E63535", 18_000, "D202"},
    {"Claire Buckman",  "E39876", 27_800, "D202"},
    {"David McClellan", "E04242", 41_500, "D101"},
    {"Rich Holcomb",    "E01234", 49_500, "D202"},
    {"Nathan Adams",    "E41298", 21_900, "D050"},
    {"Richard Potter",  "E43128", 15_900, "D101"},
    {"David Motsinger", "E27002", 19_250, "D202"},
    {"Tim Sampair",     "E03033", 27_000, "D101"},
    {"Kim Arlich",      "E10001", 57_000, "D190"},
    {"Timothy Grove",   "E16398", 29_900, "D190"}];

void main(in string[] args) {
  immutable n = (args.length == 2) ? to!int(args[1]) : 3;

  Employee[][string] departments;
  foreach (immutable rec; data)
    departments[rec.department] ~= rec;

  foreach (dep, recs; departments) {
    recs.topN!q{a.salary > b.salary}(n);
    writefln("Department %s\n  %(%s\n  %)\n", dep, recs.take(n));
  }
}


type Employee(name,id,salary,department) with Lookup

func Employee.ToString() {
    "$\(this.salary) (name: \(this.name), id: \(this.id), department: \(this.department)"
}

let employees = [
    Employee("Tyler Bennett","E10297",32000,"D101"),
    Employee("John Rappl","E21437",47000,"D050"),
    Employee("George Woltman","E00127",53500,"D101"),
    Employee("Adam Smith","E63535",18000,"D202"),
    Employee("Claire Buckman","E39876",27800,"D202"),
    Employee("David McClellan","E04242",41500,"D101"),
    Employee("Rich Holcomb","E01234",49500,"D202"),
    Employee("Nathan Adams","E41298",21900,"D050"),
    Employee("Richard Potter","E43128",15900,"D101"),
    Employee("David Motsinger","E27002",19250,"D202"),
    Employee("Tim Sampair","E03033",27000,"D101"),
    Employee("Kim Arlich","E10001",57000,"D190"),
    Employee("Timothy Grove","E16398",29900,"D190")
]

func topNSalaries(n) {
    //We sort employees based on salary
    employees.Sort((x,y) => y.salary - x.salary)
    let max =
        if n > employees.Length() - 1 {
            employees.Length() - 1
        } else {
            n
        }
    for i in 0..max {
        yield employees[i]
    }
}

var seq = topNSalaries(5)

for e in seq {
    print(e)
}


/** Turn a list of arrays into a list of maps with the given keys. */
def addKeys(keys, rows) {
  def res := [].diverge()
  for row in rows { res.push(__makeMap.fromColumns(keys, row)) }
  return res.snapshot()
}

def data := addKeys(
  ["name",            "id",  "salary", "dept"],
 [["Tyler Bennett",   "E10297", 32000, "D101"],
  ["John Rappl",      "E21437", 47000, "D050"],
  ["George Woltman",  "E00127", 53500, "D101"],
  ["Adam Smith",      "E63535", 18000, "D202"],
  ["Claire Buckman",  "E39876", 27800, "D202"],
  ["David McClellan", "E04242", 41500, "D101"],
  ["Rich Holcomb",    "E01234", 49500, "D202"],
  ["Nathan Adams",    "E41298", 21900, "D050"],
  ["Richard Potter",  "E43128", 15900, "D101"],
  ["David Motsinger", "E27002", 19250, "D202"],
  ["Tim Sampair",     "E03033", 27000, "D101"],
  ["Kim Arlich",      "E10001", 57000, "D190"],
  ["Timothy Grove",   "E16398", 29900, "D190"]])

def topSalaries(n, out) {
    var groups := [].asMap()
    for row in data {
        def [=> salary, => dept] | _ := row
        def top := groups.fetch(dept, fn {[]}).with([-salary, row]).sort()
        groups with= (dept, top.run(0, top.size().min(n)))
    }
    for dept => group in groups.sortKeys() {
        out.println(`Department $dept`)
        out.println(`---------------`)
        for [_, row] in group {
          out.println(`${row["id"]}  $$${row["salary"]}  ${row["name"]}`)
        }
        out.println()
    }
}


(lib 'struct) ;; tables are based upon structures
(lib 'sql)  ;; sql-select function

;; input table
(define emps  (make-table (struct emp (name id salary dept))))
;; output table
(define high  (make-table (struct out (dept name salary))))

;; sort/group procedure
(define (get-high num-records: N into: high)
(sql-select emp.dept emp.name emp.salary
  from emps
  group-by emp.dept
  order-by emp.salary desc limit N into high))


import system'collections;
import system'routines;
import extensions;
import extensions'routines;
import extensions'text;

class Employee
{
    prop string Name;
    prop string ID;
    prop int    Salary;
    prop string Department;

    string toPrintable()
        = new StringWriter()
            .writePaddingRight(Name, 25)
            .writePaddingRight(ID, 12)
            .writePaddingRight(Salary.toPrintable(), 12)
            .write:Department;
}

extension reportOp
{
    topNPerDepartment(n)
        = self.groupBy:(x => x.Department ).selectBy:(x)
        {
            ^ new {
                Department = x.Key;

                Employees
                    = x.orderBy:(f,l => f.Salary > l.Salary ).top(n).summarize(new ArrayList());
            }
        };
}

public program()
{
    var employees := new Employee[]
    {
        new Employee{ this Name := "Tyler Bennett"; this ID := "E10297"; this Salary:=32000; this Department:="D101";},
        new Employee{ this Name := "John Rappl"; this ID := "E21437"; this Salary:=47000; this Department:="D050";},
        new Employee{ this Name := "George Woltman"; this ID := "E00127"; this Salary:=53500; this Department:="D101";},
        new Employee{ this Name := "Adam Smith"; this ID := "E63535"; this Salary:=18000; this Department:="D202";},
        new Employee{ this Name := "Claire Buckman"; this ID := "E39876"; this Salary:=27800; this Department:="D202";},
        new Employee{ this Name := "David McClellan"; this ID := "E04242"; this Salary:=41500; this Department:="D101";},
        new Employee{ this Name := "Rich Holcomb"; this ID := "E01234"; this Salary:=49500; this Department:="D202";},
        new Employee{ this Name := "Nathan Adams"; this ID := "E41298"; this Salary:=21900; this Department:="D050";},
        new Employee{ this Name := "Richard Potter"; this ID := "E43128"; this Salary:=15900; this Department:="D101";},
        new Employee{ this Name := "David Motsinger"; this ID := "E27002"; this Salary:=19250; this Department:="D202";},
        new Employee{ this Name := "Tim Sampair"; this ID := "E03033"; this Salary:=27000; this Department:="D101";},
        new Employee{ this Name := "Kim Arlich"; this ID := "E10001"; this Salary:=57000; this Department:="D190";},
        new Employee{ this Name := "Timothy Grove"; this ID := "E16398"; this Salary:=29900; this Department:="D190";}
    };

    employees.topNPerDepartment:2.forEach:(info)
    {
        console.printLine("Department: ",info.Department);

        info.Employees.forEach:printingLn;

        console.writeLine:"---------------------------------------------"
    };

    console.readChar()
}


defmodule TopRank do
  def per_groupe(data, n) do
    String.split(data, ~r/(\n|\r\n|\r)/, trim: true)
    |> Enum.drop(1)
    |> Enum.map(fn person -> String.split(person,",") end)
    |> Enum.group_by(fn person -> department(person) end)
    |> Enum.each(fn {department,group} ->
         IO.puts "Department: #{department}"
         Enum.sort_by(group, fn person -> -salary(person) end)
         |> Enum.take(n)
         |> Enum.each(fn person -> IO.puts str_format(person) end)
       end)
  end

  defp salary([_,_,x,_]), do: String.to_integer(x)
  defp department([_,_,_,x]), do: x
  defp str_format([a,b,c,_]), do: "  #{a} - #{b} - #{c} annual salary"
end

data = """
Employee Name,Employee ID,Salary,Department
Tyler Bennett,E10297,32000,D101
John Rappl,E21437,47000,D050
George Woltman,E00127,53500,D101
Adam Smith,E63535,18000,D202
Claire Buckman,E39876,27800,D202
David McClellan,E04242,41500,D101
Rich Holcomb,E01234,49500,D202
Nathan Adams,E41298,21900,D050
Richard Potter,E43128,15900,D101
David Motsinger,E27002,19250,D202
Tim Sampair,E03033,27000,D101
Kim Arlich,E10001,57000,D190
Timothy Grove,E16398,29900,D190
"""
TopRank.per_groupe(data, 3)


<-module( top_rank_per_group  ).

-export( [employees/0, employees_in_department/2, highest_payed/2, task/1] ).

-record( employee, {name, id, salery, department} ).

employees() ->
    [#employee{name="Tyler Bennett", id="E10297", salery=32000, department="D101"},
        #employee{name="John Rappl", id="E21437", salery=47000, department="D101"},
        #employee{name="George Woltman", id="E00127", salery=53500, department="D050"},
        #employee{name="Adam Smith", id="E63535", salery=18000, department="D202"},
        #employee{name="Claire Buckman", id="E39876", salery=27800, department="D202"},
        #employee{name="David McClellan", id="E04242", salery=41500, department="D101"},
        #employee{name="Rich Holcomb", id="E01234", salery=49500, department="D202"},
        #employee{name="Nathan Adams", id="E41298", salery=21900, department="D050"},
        #employee{name="Richard Potter", id="E43128", salery=15900, department="D101"},
        #employee{name="David Motsinger", id="E27002", salery=19250, department="D202"},
        #employee{name="Tim Sampair", id="E03033", salery=27000, department="D101"},
        #employee{name="Kim Arlich", id="E10001", salery=57000, department="D190"},
        #employee{name="Timothy Grove", id="E16398", salery=29900, department="D190"}].

employees_in_department( Department, Employees ) -> [X || #employee{department=D}=X <- Employees, D =:= Department].

highest_payed( N, Employees ) ->
    {Highest, _T} = lists:split( N, lists:reverse(lists:keysort(#employee.salery, Employees)) ),
    Highest.

task( N ) ->
    Employees = employees(),
    Departments = lists:usort( [X || #employee{department=X} <- Employees] ),
    Employees_in_departments = [employees_in_department(X, Employees) || X <- Departments],
    Highest_payed_in_departments = [highest_payed(N, Xs) || Xs <- Employees_in_departments],
    [task_write(X) || X <- Highest_payed_in_departments].

task_write( Highest_payeds ) ->
    [io:fwrite( "~p ~p: ~p~n", [Department, Salery, Name]) || #employee{department=Department, salery=Salery, name=Name} <- Highest_payeds],
    io:nl().


USING: accessors assocs fry io kernel math.parser sequences
sorting ;
IN: top-rank

TUPLE: employee name id salary department ;

CONSTANT: employees {
        T{ employee f "Tyler Bennett" "E10297" 32000 "D101" }
        T{ employee f "John Rappl" "E21437" 47000 "D050" }
        T{ employee f "George Woltman" "E00127" 53500 "D101" }
        T{ employee f "Adam Smith" "E63535" 18000 "D202" }
        T{ employee f "Claire Buckman" "E39876" 27800 "D202" }
        T{ employee f "David McClellan" "E04242" 41500 "D101" }
        T{ employee f "Rich Holcomb" "E01234" 49500 "D202" }
        T{ employee f "Nathan Adams" "E41298" 21900 "D050" }
        T{ employee f "Richard Potter" "E43128" 15900 "D101" }
        T{ employee f "David Motsinger" "E27002" 19250 "D202" }
        T{ employee f "Tim Sampair" "E03033" 27000 "D101" }
        T{ employee f "Kim Arlich" "E10001" 57000 "D190" }
        T{ employee f "Timothy Grove" "E16398" 29900 "D190" }
    }

: group-by ( seq quot -- hash )
    H{ } clone [ '[ dup @ _ push-at ] each ] keep ; inline

: prepare-departments ( seq -- departments )
    [ department>> ] group-by
    [ [ salary>> ] inv-sort-with ] assoc-map ;

: first-n-each ( seq n quot -- )
    [ short head-slice ] dip each ; inline

: main ( -- )
    employees prepare-departments [
        [ "Department " write write ":" print ] dip
        3 [
            [ id>> write "  $" write ]
            [ salary>> number>string write "  " write ]
            [ name>> print ] tri
        ] first-n-each
        nl
    ] assoc-each ;


\ Written in ANS-Forth; tested under VFX.
\ Requires the novice package: http://www.forth.org/novice.html
\ The following should already be done:
\ include novice.4th
\ include list.4th

marker TopRank.4th

\ This demonstrates how I typically use lists. A program such as this does not need any explicit iteration, so it is more like Factor than C.
\ I would define high-level languages as those that allow programs to be written without explicit iteration. Iteration is a major source of bugs.
\ The C library has QSORT that hides iteration, but user-written code very rarely uses this technique, and doesn't in the TopRank example.

\ ******
\ ****** The following defines our data-structure.
\ ****** Pretty much every struct definition has these basic functions.
\ ******

list
    w field .name       \ string
    w field .id         \ string
    w field .salary     \ integer
    w field .dept       \ string
constant employee

: init-employee ( name id salary department node -- node )
    init-list >r
    hstr    [email protected] .dept !
            [email protected] .salary !
    hstr    [email protected] .id !
    hstr    [email protected] .name !
    r> ;

: new-employee ( name id salary dept -- node )
    employee alloc
    init-employee ;

: <kill-employee> ( node -- )
    dup .name @     dealloc
    dup .id @       dealloc
    dup .dept @     dealloc
    dealloc ;

: kill-employee ( head -- )
    each[  <kill-employee>  ]each ;

: <clone-employee> ( node -- new-node )
    clone-node
    dup .name @     hstr    over .name !
    dup .id @       hstr    over .id !
    dup .dept @     hstr    over .dept ! ;

: clone-employee ( head -- new-head )
    nil
    swap each[  <clone-employee> link  ]each ;

: <show-employee> ( node -- )
    dup .id @       count type  4 spaces
    dup .dept @     count type  4 spaces
    dup .salary @   .           4 spaces
    dup .name @     count type  cr
    drop ;

: show-employee ( head -- )
    cr
    each[  <show-employee>  ]each ;

\ ******
\ ****** The following code is specific to the query that we want to do in this example problem.
\ ******

: employee-dept-salary ( new-node node -- new-node ? )                      \ for use by FIND-PRIOR or INSERT-ORDERED
    2dup
    .dept @ count   rot .dept @ count   compare     ?dup if  A>B =  nip exit then
    .salary @       over .salary @      < ;

: <top> ( n rank current-dept head node -- n rank current-dept head )
    2>r                         \ -- n rank current-dept
    dup count  [email protected] .dept @ count  compare  A=B <> if                         \ we have a new department
        2drop                                                               \ discard RANK and CURRENT-DEPT
        0  [email protected] .dept @  then                                                 \ start again with a new RANK and CURRENT-DEPT
    rover rover > if                                                        \ if N > RANK then it is good
        r> r>  over             \ -- n rank current-dept node head node
        <clone-employee> link   \ -- n rank current-dept node head
        >r >r  then             \ -- n rank current-dept
    swap 1+  swap                                                           \ increment RANK
    rdrop  r> ;                 \ -- n rank current-dept head

: top ( n head -- new-head )    \ make a new list of the top N salary earners in each dept      \ requires that list be sorted by dept-salary
    >r
    0  c" xxx"  nil             \ -- n rank current-dept new-head           \ initially for an invalid department
    r>  ['] <top>  each
    3nip ;

\ ******
\ ****** The following is a test of the program using sample data.
\ ******

nil  ' employee-dept-salary
c" Tyler Bennett"       c" E10297"  32000  c" D101"     new-employee  insert-ordered
c" John Rappl"          c" E21437"  47000  c" D050"     new-employee  insert-ordered
c" George Woltman"      c" E00127"  53500  c" D101"     new-employee  insert-ordered
c" Adam Smith"          c" E63535"  18000  c" D202"     new-employee  insert-ordered
c" Claire Buckman"      c" E39876"  27800  c" D202"     new-employee  insert-ordered
c" David McClellan"     c" E04242"  41500  c" D101"     new-employee  insert-ordered
c" Rich Holcomb"        c" E01234"  49500  c" D202"     new-employee  insert-ordered
c" Nathan Adams"        c" E41298"  21900  c" D050"     new-employee  insert-ordered
c" Richard Potter"      c" E43128"  15900  c" D101"     new-employee  insert-ordered
c" David Motsinger"     c" E27002"  19250  c" D202"     new-employee  insert-ordered
c" Tim Sampair"         c" E03033"  27000  c" D101"     new-employee  insert-ordered
c" Kim Arlich"          c" E10001"  57000  c" D190"     new-employee  insert-ordered
c" Timothy Grove"       c" E16398"  29900  c" D190"     new-employee  insert-ordered
drop  constant test-data

cr .( N = 0 )
0 test-data top  dup show-employee  kill-employee

cr .( N = 1 )
1 test-data top  dup show-employee  kill-employee

cr .( N = 2 )
2 test-data top  dup show-employee  kill-employee

cr .( N = 3 )
3 test-data top  dup show-employee  kill-employee

test-data kill-employee


#define N 3      'show the top three employees of each rank

'here is all the data to be read in

data "Tyler Bennett","E10297",32000,"D101"
data "John Rappl","E21437",47000,"D050"
data "George Woltman","E00127",53500,"D101"
data "Adam Smith","E63535",18000,"D202"
data "Claire Buckman","E39876",27800,"D202"
data "David McClellan","E04242",41500,"D101"
data "Rich Holcomb","E01234",49500,"D202"
data "Nathan Adams","E41298",21900,"D050"
data "Richard Potter","E43128",15900,"D101"
data "David Motsinger","E27002",19250,"D202"
data "Tim Sampair","E03033",27000,"D101"
data "Kim Arlich","E10001",57000,"D190"
data "Timothy Grove","E16398",29900,"D190"

type employee
    'define a data type for employees
    nm as string*32   'name
    en as string*6    'employee number
    sl as uinteger    'salary
    dp as string*4    'department
    fl as boolean      'a flag
end type

dim as employee emp(1 to 13)
dim as uinteger e, d, x, ce, cs
dim as string*4 dept(1 to 4) = {"D050", "D101", "D190", "D202"}

for e = 1 to 13
    'put all the employee data into an array
    read emp(e).nm
    read emp(e).en
    read emp(e).sl
    read emp(e).dp
    emp(e).fl = false
next e

for d = 1 to 4    'look at each department
    print "Department ";dept(d);":"
    for x = 1 to N    'top N employees
        cs = 0
        ce = 0
        for e = 1 to 13    'look through employees
            if emp(e).dp = dept(d) andalso emp(e).fl = false andalso emp(e).sl > cs then
                emp(ce).fl = false 'unflag the previous champion so they can be found on the next pass
                ce = e
                cs = emp(e).sl
                emp(e).fl = true   'flag this employee so that on the next pass we can get the next richest
            endif
        next e
        if ce>0 then print emp(ce).nm;"  ";emp(ce).en;"  ";emp(ce).sl;"  ";emp(ce).dp
    next x
    print
next d


data Employee( name, id, salary, dept )

employees = [
  Employee( 'Tyler Bennett', 'E10297', 32000, 'D101' ),
  Employee( 'John Rappl', 'E21437', 47000, 'D050' ),
  Employee( 'George Woltman', 'E00127', 53500, 'D101' ),
  Employee( 'Adam Smith', 'E63535', 18000, 'D202' ),
  Employee( 'Claire Buckman', 'E39876', 27800, 'D202' ),
  Employee( 'David McClellan', 'E04242', 41500, 'D101' ),
  Employee( 'Rich Holcomb', 'E01234', 49500, 'D202' ),
  Employee( 'Nathan Adams', 'E41298', 21900, 'D050' ),
  Employee( 'Richard Potter', 'E43128', 15900, 'D101' ),
  Employee( 'David Motsinger', 'E27002', 19250, 'D202' ),
  Employee( 'Tim Sampair', 'E03033', 27000, 'D101' ),
  Employee( 'Kim Arlich', 'E10001', 57000, 'D190' ),
  Employee( 'Timothy Grove', 'E16398', 29900, 'D190' )
  ]

N = 2

for (dept, empl) <- employees.groupBy( e -> e.dept ).>toList().sortWith( (<) )
  println( dept )

  for e <- empl.sortWith( \a, b -> a.salary > b.salary ).take( N )
    printf( "    %-16s  %6s  %7d\n", e.name, e.id, e.salary )

  println()


package main

import (
    "fmt"
    "sort"
)

// language-native data description
type Employee struct {
    Name, ID string
    Salary   int
    Dept     string
}

type EmployeeList []*Employee

var data = EmployeeList{
    {"Tyler Bennett", "E10297", 32000, "D101"},
    {"John Rappl", "E21437", 47000, "D050"},
    {"George Woltman", "E00127", 53500, "D101"},
    {"Adam Smith", "E63535", 18000, "D202"},
    {"Claire Buckman", "E39876", 27800, "D202"},
    {"David McClellan", "E04242", 41500, "D101"},
    {"Rich Holcomb", "E01234", 49500, "D202"},
    {"Nathan Adams", "E41298", 21900, "D050"},
    {"Richard Potter", "E43128", 15900, "D101"},
    {"David Motsinger", "E27002", 19250, "D202"},
    {"Tim Sampair", "E03033", 27000, "D101"},
    {"Kim Arlich", "E10001", 57000, "D190"},
    {"Timothy Grove", "E16398", 29900, "D190"},
    // Extra data to demonstrate ties
    {"Tie A", "E16399", 29900, "D190"},
    {"Tie B", "E16400", 29900, "D190"},
    {"No Tie", "E16401", 29899, "D190"},
}

// We only need one type of ordering/grouping for this task so we could directly
// implement sort.Interface on EmployeeList (or a byDeptSalary alias type) with
// the appropriate Less method.
//
// Instead, we'll add a bit here that makes it easier to use arbitrary orderings.
// This is like the "SortKeys" Planet sorting example in the sort package
// documentation, see https://golang.org/pkg/sort

type By func(e1, e2 *Employee) bool
type employeeSorter struct {
    list EmployeeList
    by   func(e1, e2 *Employee) bool
}

func (by By) Sort(list EmployeeList)         { sort.Sort(&employeeSorter{list, by}) }
func (s *employeeSorter) Len() int           { return len(s.list) }
func (s *employeeSorter) Swap(i, j int)      { s.list[i], s.list[j] = s.list[j], s.list[i] }
func (s *employeeSorter) Less(i, j int) bool { return s.by(s.list[i], s.list[j]) }

// For this specific task we could just write the data to an io.Writer
// but in general it's better to return the data in a usable form (for
// example, perhaps other code want's to do something like compare the
// averages of the top N by department).
//
// So we go through the extra effort of returning an []EmployeeList, a
// list of employee lists, one per deparment. The lists are trimmed to
// to the top 'n', which can be larger than n if there are ties for the
// nth salary (callers that don't care about ties could just trim more.)
func (el EmployeeList) TopSalariesByDept(n int) []EmployeeList {
    if n <= 0 || len(el) == 0 {
        return nil
    }
    deptSalary := func(e1, e2 *Employee) bool {
        if e1.Dept != e2.Dept {
            return e1.Dept < e2.Dept
        }
        if e1.Salary != e2.Salary {
            return e1.Salary > e2.Salary
        }
        // Always have some unique field as the last one in a sort list
        return e1.ID < e2.ID
    }

    // We could just sort the data in place for this task. But
    // perhaps messing with the order is undesirable or there is
    // other concurrent access. So we'll make a copy and sort that.
    // It's just pointers so the amount to copy is relatively small.
    sorted := make(EmployeeList, len(el))
    copy(sorted, el)
    By(deptSalary).Sort(sorted)

    perDept := []EmployeeList{}
    var lastDept string
    var lastSalary int
    for _, e := range sorted {
        if e.Dept != lastDept || len(perDept) == 0 {
            lastDept = e.Dept
            perDept = append(perDept, EmployeeList{e})
        } else {
            i := len(perDept) - 1
            if len(perDept[i]) >= n && e.Salary != lastSalary {
                continue
            }
            perDept[i] = append(perDept[i], e)
            lastSalary = e.Salary
        }
    }
    return perDept
}

func main() {
    const n = 3
    top := data.TopSalariesByDept(n)
    if len(top) == 0 {
        fmt.Println("Nothing to show.")
        return
    }
    fmt.Printf("Top %d salaries per department\n", n)
    for _, list := range top {
        fmt.Println(list[0].Dept)
        for _, e := range list {
            fmt.Printf("    %s %16s %7d\n", e.ID, e.Name, e.Salary)
        }
    }
}


def displayRank(employees, number) {
    employees.groupBy { it.Department }.sort().each { department, staff ->
        println "Department $department"
        println "    Name                ID      Salary"
        staff.sort { e1, e2 -> e2.Salary <=> e1.Salary }
        staff[0..<Math.min(number, staff.size())].each { e ->
           println "    ${e.Name.padRight(20)}${e.ID}${sprintf('%8d', e.Salary)}"
        }
        println()
    }
}

def employees = [
        [Name: 'Tyler Bennett', ID: 'E10297', Salary: 32000, Department: 'D101'],
        [Name: 'John Rappl', ID: 'E21437', Salary: 47000, Department: 'D050'],
        [Name: 'George Woltman', ID: 'E00127', Salary: 53500, Department: 'D101'],
        [Name: 'Adam Smith', ID: 'E63535', Salary: 18000, Department: 'D202'],
        [Name: 'Claire Buckman', ID: 'E39876', Salary: 27800, Department: 'D202'],
        [Name: 'David McClellan', ID: 'E04242', Salary: 41500, Department: 'D101'],
        [Name: 'Rich Holcomb', ID: 'E01234', Salary: 49500, Department: 'D202'],
        [Name: 'Nathan Adams', ID: 'E41298', Salary: 21900, Department: 'D050'],
        [Name: 'Richard Potter', ID: 'E43128', Salary: 15900, Department: 'D101'],
        [Name: 'David Motsinger', ID: 'E27002', Salary: 19250, Department: 'D202'],
        [Name: 'Tim Sampair', ID: 'E03033', Salary: 27000, Department: 'D101'],
        [Name: 'Kim Arlich', ID: 'E10001', Salary: 57000, Department: 'D190'],
        [Name: 'Timothy Grove', ID: 'E16398', Salary: 29900, Department: 'D190']
]
displayRank(employees, 3)


import Data.List (sortBy, groupBy)

import Text.Printf (printf)

import Data.Ord (comparing)

import Data.Function (on)

type ID = Int

type DEP = String

type NAME = String

type SALARY = Double

data Employee = Employee
  { nr :: ID
  , dep :: DEP
  , name :: NAME
  , sal :: SALARY
  }

employees :: [Employee]
employees =
  fmap
    (\(i, d, n, s) -> Employee i d n s)
    [ (1001, "AB", "Janssen A.H.", 41000)
    , (101, "KA", "'t Woud B.", 45000)
    , (1013, "AB", "de Bont C.A.", 65000)
    , (1101, "CC", "Modaal A.M.J.", 30000)
    , (1203, "AB", "Anders H.", 50000)
    , (100, "KA", "Ezelbips P.J.", 52000)
    , (1102, "CC", "Zagt A.", 33000)
    , (1103, "CC", "Ternood T.R.", 21000)
    , (1104, "CC", "Lageln M.", 23000)
    , (1105, "CC", "Amperwat A.", 19000)
    , (1106, "CC", "Boon T.J.", 25000)
    , (1107, "CC", "Beloop L.O.", 31000)
    , (1009, "CD", "Janszoon A.", 38665)
    , (1026, "CD", "Janszen H.P.", 41000)
    , (1011, "CC", "de Goeij J.", 39000)
    , (106, "KA", "Pragtweik J.M.V.", 42300)
    , (111, "KA", "Bakeuro S.", 31000)
    , (105, "KA", "Clubdrager C.", 39800)
    , (104, "KA", "Karendijk F.", 23000)
    , (107, "KA", "Centjes R.M.", 34000)
    , (119, "KA", "Tegenstroom H.L.", 39000)
    , (1111, "CD", "Telmans R.M.", 55500)
    , (1093, "AB", "de Slegte S.", 46987)
    , (1199, "CC", "Uitlaat G.A.S.", 44500)
    ]

firstN :: Int
       -> (Employee -> DEP)
       -> (Employee -> SALARY)
       -> [Employee]
       -> [[Employee]]
firstN n o1 o2 x =
  fmap
    (take n . sortBy (comparingDown o2))
    (groupBy (groupingOn o1) (sortBy (comparing o1) x))

groupingOn
  :: Eq a1
  => (a -> a1) -> a -> a -> Bool
groupingOn = ((==) `on`)

comparingDown
  :: Ord a
  => (b -> a) -> b -> b -> Ordering
comparingDown = flip . comparing

main :: IO ()
main = do
  printf "%-16s %3s %10s\n" "NAME" "DEP" "TIP"
  putStrLn $ replicate 31 '='
  mapM_ (traverse ((printf "%-16s %3s %10.2g\n" . name) <*> dep <*> sal)) $
    firstN 3 dep sal employees


CHARACTER source="Test.txt", outP='Top_rank.txt', fmt='A20,A8,i6,2x,A10'
CHARACTER name*20, employee_ID*10, department*10, temp*10
REAL ::   idx(1), N_top_salaries=3

! Open the source with 4 "," separated columns, skip line 1:
OPEN(FIle=source, Format='SL=1;4,;', LENgth=L)
ALLOCATE(idx, L)

! Sort salary column 3 descending, then department column 4, store in idx:
SORT(FIle=source, Column=3, Descending=1, Column=4, Index=idx)

! Display a spreadsheet-like scrolling dialog of the presorted source:
DLG(Text=idx, Text=source, Format=fmt, Y)

! Output the first N top salaries of each department_
OPEN(FIle=outP)
DO i = 1, L
   rank = rank + 1
   READ(FIle=source, Row=idx(i)) name, employee_ID, salary, department
   IF(temp /= department) THEN
       rank = 1
       WRITE(FIle=outP)
       temp = department
   ENDIF
   IF(rank <= N_top_salaries) THEN
       WRITE(FIle=outP, Format=fmt) name, employee_ID, salary, department
   ENDIF
ENDDO

END


record Employee(name,id,salary,dept)

procedure getEmployees ()
  employees := [
    Employee("Tyler Bennett","E10297",32000,"D101"),
    Employee("John Rappl","E21437",47000,"D050"),
    Employee("George Woltman","E00127",53500,"D101"),
    Employee("Adam Smith","E63535",18000,"D202"),
    Employee("Claire Buckman","E39876",27800,"D202"),
    Employee("David McClellan","E04242",41500,"D101"),
    Employee("Rich Holcomb","E01234",49500,"D202"),
    Employee("Nathan Adams","E41298",21900,"D050"),
    Employee("Richard Potter","E43128",15900,"D101"),
    Employee("David Motsinger","E27002",19250,"D202"),
    Employee("Tim Sampair","E03033",27000,"D101"),
    Employee("Kim Arlich","E10001",57000,"D190"),
    Employee("Timothy Grove","E16398",29900,"D190")
  ]
  return employees
end

procedure show_employee (employee)
  every writes (!employee || " ")
  write ()
end

procedure main (args)
  N := integer(args[1]) # N set from command line
  employees := getEmployees ()
  groups := set()
  every employee := !employees do insert(groups, employee.dept)

  every group := !groups do {
    write ("== Top " || N || " in group " || group)
    employeesInGroup := []
    every employee := !employees do {
      if employee.dept == group then put(employeesInGroup, employee)
    }
    # sort by third field and reverse, so highest salary comes first
    employeesInGroup := reverse(sortf(employeesInGroup, 3))
    # show the first N records, up to the end of the list
    every show_employee (!employeesInGroup[1:(1+min(N,*employeesInGroup))])
  }
end


100 PROGRAM "Employee.bas"(N)
110 LET NR=100:LET X=0
120 STRING NAME$(1 TO NR)*20,ID$(1 TO NR)*6,DEPT$(1 TO NR)*4
130 NUMERIC SALARY(1 TO NR)
140 DO UNTIL N>0 AND N<=NR
150   INPUT PROMPT "Enter the number of ranks: ":N$
160   LET N=VAL(N$)
170 LOOP
180 CALL READDATA
190 CALL SORT
200 CALL LST
210 END
220 DEF READDATA
230   LET EOF=0
240   OPEN #1:"Employee.dat"
250   WHEN EXCEPTION USE IOERROR
260     DO
270       LET X=X+1
280       INPUT #1:NAME$(X),ID$(X),SALARY(X),DEPT$(X)
290     LOOP UNTIL EOF OR X=NR
300   END WHEN
310   HANDLER IOERROR
320     IF EXTYPE<>8001 THEN PRINT EXSTRING$(EXTYPE)
330     CLOSE #1
340     LET X=X-1:LET EOF=-1
350     IF X=0 THEN PRINT "No data.":STOP
360     CONTINUE
370   END HANDLER
380 END DEF
390 DEF SORT
400   LET GAP=X:LET SW=1
410   DO WHILE GAP>1 OR SW
420     LET GAP=MAX(INT(GAP/1.3),1):LET SW=0
430     FOR I=1 TO X-GAP
440       IF DEPT$(I)>DEPT$(I+GAP) OR DEPT$(I)=DEPT$(I+GAP) AND SALARY(I)<SALARY(I+GAP) THEN
450         LET T$=NAME$(I):LET NAME$(I)=NAME$(I+GAP):LET NAME$(I+GAP)=T$
460         LET T$=DEPT$(I):LET DEPT$(I)=DEPT$(I+GAP):LET DEPT$(I+GAP)=T$
470         LET T$=ID$(I):LET ID$(I)=ID$(I+GAP):LET ID$(I+GAP)=T$
480         LET T=SALARY(I):LET SALARY(I)=SALARY(I+GAP):LET SALARY(I+GAP)=T
490         LET SW=1
500       END IF
510     NEXT
520   LOOP
530 END DEF
540 DEF LST
550   LET J=1:LET PREV$=""
560   FOR I=1 TO X
570     IF DEPT$(I)<>PREV$ THEN PRINT "Department ";DEPT$(I):LET PREV$=DEPT$(I):LET J=1
580     IF J<=N THEN PRINT "  ";NAME$(I);TAB(23);ID$(I),SALARY(I):LET J=J+1
590   NEXT
600 END DEF


NB.  Dynamically generate convenience functions
('`',,;:^:_1: N=:{.Employees) =:, (_&{"1)`'' ([^:(_ -: ])L:0)"0 _~ i.# E =: {: Employees

NB.  Show top six ranked employees in each dept
N , (<@:>"1@:|:@:((6 <. #) {. ] \: SALARY)/.~ DEPT) |: <"1&> E


import java.io.File;
import java.util.*;

public class TopRankPerGroup {

    private static class Employee {
        final String name;
        final String id;
        final String department;
        final int salary;

        Employee(String[] rec) {
            name = rec[0];
            id = rec[1];
            salary = Integer.parseInt(rec[2]);
            department = rec[3];
        }

        @Override
        public String toString() {
            return String.format("%s %s %d %s", id, name, salary, department);
        }
    }

    public static void main(String[] args) throws Exception {
        int N = args.length > 0 ? Integer.parseInt(args[0]) : 3;

        Map<String, List<Employee>> records = new TreeMap<>();
        try (Scanner sc = new Scanner(new File("data.txt"))) {
            while (sc.hasNextLine()) {
                String[] rec = sc.nextLine().trim().split(", ");

                List<Employee> lst = records.get(rec[3]);
                if (lst == null) {
                    lst = new ArrayList<>();
                    records.put(rec[3], lst);
                }
                lst.add(new Employee(rec));
            }
        }

        records.forEach((key, val) -> {
            System.out.printf("%nDepartment %s%n", key);
            val.stream()
                .sorted((a, b) -> Integer.compare(b.salary, a.salary))
                .limit(N).forEach(System.out::println);
        });
    }
}


var data = [
    {name: "Tyler Bennett",   id: "E10297", salary: 32000, dept: "D101"},
    {name: "John Rappl",      id: "E21437", salary: 47000, dept: "D050"},
    {name: "George Woltman",  id: "E00127", salary: 53500, dept: "D101"},
    {name: "Adam Smith",      id: "E63535", salary: 18000, dept: "D202"},
    {name: "Claire Buckman",  id: "E39876", salary: 27800, dept: "D202"},
    {name: "David McClellan", id: "E04242", salary: 41500, dept: "D101"},
    {name: "Rich Holcomb",    id: "E01234", salary: 49500, dept: "D202"},
    {name: "Nathan Adams",    id: "E41298", salary: 21900, dept: "D050"},
    {name: "Richard Potter",  id: "E43128", salary: 15900, dept: "D101"},
    {name: "David Motsinger", id: "E27002", salary: 19250, dept: "D202"},
    {name: "Tim Sampair",     id: "E03033", salary: 27000, dept: "D101"},
    {name: "Kim Arlich",      id: "E10001", salary: 57000, dept: "D190"},
    {name: "Timothy Grove",   id: "E16398", salary: 29900, dept: "D190"},
];

function top_rank(n) {
    var by_dept = group_by_dept(data);
    for (var dept in by_dept) {
        output(dept);
        for (var i = 0; i < n && i < by_dept[dept].length; i++) {
            var emp = by_dept[dept][i];
            output(emp.name + ", id=" + emp.id + ", salary=" + emp.salary);
        }
        output("");
    }
}

// group by dept, and sort by salary
function group_by_dept(data) {
    var by_dept = {};
    for (var idx in data)  {
        var dept = data[idx].dept;
        if ( ! has_property(by_dept, dept)) {
            by_dept[dept] = new Array();
        }
        by_dept[dept].push(data[idx]);
    }
    for (var dept in by_dept) {
        // numeric sort
        by_dept[dept].sort(function (a,b){return b.salary - a.salary});
    }
    return by_dept;
}

function has_property(obj, propname) {
    return typeof(obj[propname]) != "undefined";
}

function output(str) {
    try {
        WScript.Echo(str);  // WSH
    } catch(err) {
        print(str);  // Rhino
    }
}

top_rank(3);


#!/usr/bin/env jsish
/* Top rank per group, in Jsish */
function top_rank(n) {
    var by_dept = group_by_dept(data);
    for (var dept in by_dept) {
        puts(dept);
        for (var i = 0; i < n && i < by_dept[dept].length; i++) {
            var emp = by_dept[dept][i];
            puts(emp.name + ", id=" + emp.id + ", salary=" + emp.salary);
        }
        puts("");
    }
}

// group by dept, and sort by salary
function group_by_dept(data) {
    var by_dept = {};
    for (var idx in data)  {
        var dept = data[idx].dept;
        if ( !by_dept.hasOwnProperty(dept)) {
            by_dept[dept] = new Array();
        }
        by_dept[dept].push(data[idx]);
    }
    for (var dept in by_dept) {
        by_dept[dept].sort(function (a,b) { return b.salary - a.salary; });
    }
    return by_dept;
}

if (Interp.conf('unitTest')) {
    var data = [
        {name: "Tyler Bennett",   id: "E10297", salary: 32000, dept: "D101"},
        {name: "John Rappl",      id: "E21437", salary: 47000, dept: "D050"},
        {name: "George Woltman",  id: "E00127", salary: 53500, dept: "D101"},
        {name: "Adam Smith",      id: "E63535", salary: 18000, dept: "D202"},
        {name: "Claire Buckman",  id: "E39876", salary: 27800, dept: "D202"},
        {name: "David McClellan", id: "E04242", salary: 41500, dept: "D101"},
        {name: "Rich Holcomb",    id: "E01234", salary: 49500, dept: "D202"},
        {name: "Nathan Adams",    id: "E41298", salary: 21900, dept: "D050"},
        {name: "Richard Potter",  id: "E43128", salary: 15900, dept: "D101"},
        {name: "David Motsinger", id: "E27002", salary: 19250, dept: "D202"},
        {name: "Tim Sampair",     id: "E03033", salary: 27000, dept: "D101"},
        {name: "Kim Arlich",      id: "E10001", salary: 57000, dept: "D190"},
        {name: "Timothy Grove",   id: "E16398", salary: 29900, dept: "D190"}
    ];

    top_rank(3);
}

/*
=!EXPECTSTART!=
D050
John Rappl, id=E21437, salary=47000
Nathan Adams, id=E41298, salary=21900

D101
George Woltman, id=E00127, salary=53500
David McClellan, id=E04242, salary=41500
Tyler Bennett, id=E10297, salary=32000

D190
Kim Arlich, id=E10001, salary=57000
Timothy Grove, id=E16398, salary=29900

D202
Rich Holcomb, id=E01234, salary=49500
Claire Buckman, id=E39876, salary=27800
David Motsinger, id=E27002, salary=19250

=!EXPECTEND!=
*/


F print_verse(n)
   V l = [String(‘b’), ‘f’, ‘m’]
   V s = n[1..]
   V? i = l.find(n[0].lowercase())
   I i != N
      l[i] = ‘’
   E I n[0] C (‘A’, ‘E’, ‘I’, ‘O’, ‘U’)
      s = n.lowercase()
   print("#., #., bo-#.#.\nBanana-fana fo-#.#.\nFee-fi-mo-#.#.\n#.!\n".format(n, n, l[0], s, l[1], s, l[2], s, n))

L(n) [‘Gary’, ‘Earl’, ‘Billy’, ‘Felix’, ‘Mary’]
   print_verse(n)


# v0.6.0

using DataFrames

df = DataFrame(
EmployeeName=["Tyler Bennett", "John Rappl", "George Woltman", "Adam Smith",
"Claire Buckman", "David McClellan", "Rich Holcomb", "Nathan Adams",
"Richard Potter", "David Motsinger", "Tim Sampair", "Kim Arlich", "Timothy Grove"],
EmployeeID = ["E10297", "E21437", "E00127", "E63535", "E39876", "E04242",
"E01234", "E41298", "E43128", "E27002", "E03033", "E10001", "E16398"],
Salary = [32000, 47000, 53500, 18000, 27800, 41500, 49500, 21900, 15900, 19250,
27000, 57000, 29900],
Department = ["D101", "D050", "D101", "D202", "D202", "D101", "D202", "D050",
"D101", "D202", "D101", "D190", "D190"])

# To get only values
function firstnby(n::Int, y::Array, by::Array)
    # Check that each value belong to one and one only class
    if length(y) != length(by); error("y and by must have the same length"); end

    # Initialize resulting dictionary
    rst = Dict{eltype(by), Array{eltype(y)}}()

    # For each class...
    for cl in unique(by)
        # ...select the values of that class...
        i = find(x -> x == cl, by)
        # ...sort them and store them in result...
        rst[cl] = sort(y[i]; rev=true)
        # ...if length is greater than n select only first n elements
        if length(i) > n
            rst[cl] = rst[cl][1:n]
        end
    end
    return rst
end

for (cl, val) in firstnby(3, Array(df[:Salary]), Array(df[:Department]))
    println("$cl => $val")
end

# To get the full row...
function firstnby(n::Int, df::DataFrame, y::Symbol, by::Symbol)
    rst = Dict{eltype(df[by]), DataFrame}()

    for cl in unique(df[by])
        i = find(x -> x == cl, df[by])
        rst[cl] = sort(df[i, :]; cols=order(y; rev=true))
        if length(i) > n
            rst[cl] = rst[cl][1:n, :]
        end
    end
    return rst
end

for (cl, data) in firstnby(3, df, :Salary, :Department)
    println("\n$cl:\n$data")
end


with Ada.Characters.Handling;
with Ada.Strings.Unbounded;
with Ada.Text_IO;

procedure The_Name_Game
is
   package ACH renames Ada.Characters.Handling;
   package ASU renames Ada.Strings.Unbounded;
   function "+"(input : in String) return ASU.Unbounded_String renames ASU.To_Unbounded_String;
   function "+"(input : in ASU.Unbounded_String) return String renames ASU.To_String;

   function Normalize_Case(input : in String) return String is
   begin
      return ACH.To_Upper(input(input'First))
        & ACH.To_Lower(input(input'First + 1 .. input'Last));
   end Normalize_Case;

   function Transform(input : in String; letter : in Character) return String is
   begin
      case input(input'First) is
         when 'A' | 'E' | 'I' | 'O' | 'U' =>
            return letter & ACH.To_Lower(input);
         when others =>
            if ACH.To_Lower(input(input'First)) = letter then
               return input(input'First + 1 .. input'Last);
            else
               return letter & input(input'First + 1 .. input'Last);
            end if;
      end case;
   end Transform;

   procedure Lyrics(name : in String)
   is
      normalized : constant String := Normalize_Case(name);
   begin
      Ada.Text_IO.Put_Line(normalized & ", " & normalized & ", bo-" & Transform(normalized, 'b'));
      Ada.Text_IO.Put_Line("Banana-fana, fo-" & Transform(normalized, 'f'));
      Ada.Text_IO.Put_Line("fi-fee-mo-" & Transform(normalized, 'm'));
      Ada.Text_IO.Put_Line(normalized & '!');
      Ada.Text_IO.New_Line;
   end Lyrics;

   names : constant array(1 .. 5) of ASU.Unbounded_String :=
     (+"Gary",
      +"EARL",
      +"billy",
      +"FeLiX",
      +"Mary");
begin
   for name of names loop
      Lyrics(+name);
   end loop;
end The_Name_Game;


main:(
  PROC print lyrics = (STRING name) VOID:
    BEGIN
      PROC change name = (STRING name, CHAR initial) STRING:
        BEGIN
          CHAR lower first = to lower(name[1]);
          IF char in string(lower first, NIL, "aeiou") THEN
            lower first + name[2:]
          ELIF lower first = initial THEN
            name[2:]
          ELSE
            initial + name[2:]
          FI
        END;

    print((name, ", ", name, ", bo-", change name(name, "b"), new line,
           "Banana-fana fo-", change name(name, "f"), new line,
           "Fee-fi-mo-", change name(name, "m"), new line,
           name, "!", new line))
  END;

  []STRING names = ("Gary", "Earl", "Billy", "Felix", "Mary");

  FOR i FROM LWB names TO UPB names DO
    print lyrics(names[i]);
    print(new line)
  OD
)


// version 1.1.2

data class Employee(val name: String, val id: String, val salary: Int, val dept: String)

const val N = 2 //say

fun main(args: Array<String>) {
    val employees = listOf(
        Employee("Tyler Bennett", "E10297", 32000, "D101"),
        Employee("John Rappl", "E21437", 47000, "D050"),
        Employee("George Woltman" , "E00127", 53500, "D101"),
        Employee("Adam Smith", "E63535", 18000, "D202"),
        Employee("Claire Buckman", "E39876", 27800, "D202"),
        Employee("David McClellan", "E04242", 41500, "D101"),
        Employee("Rich Holcomb", "E01234", 49500, "D202"),
        Employee("Nathan Adams", "E41298", 21900, "D050"),
        Employee("Richard Potter", "E43128", 15900, "D101"),
        Employee("David Motsinger", "E27002", 19250, "D202"),
        Employee("Tim Sampair", "E03033", 27000, "D101"),
        Employee("Kim Arlich", "E10001", 57000, "D190"),
        Employee("Timothy Grove", "E16398", 29900, "D190")
    )
    val employeesByDept = employees.sortedBy { it.dept }.groupBy { it.dept }
    println("Highest $N salaries by department:\n")
    for ((key, value) in employeesByDept) {
        val topRanked = value.sortedByDescending { it.salary }.take(N)
        println("Dept $key => ")
        for (i in 0 until N) with (topRanked[i]) { println("${name.padEnd(15)} $id $salary") }
        println()
    }
}


for i, x in StrSplit("Gary,Earl,Billy,Felix,Mary", ","){
	BFM := false
	if (SubStr(x, 1, 1) ~= "i)^[AEIOU]")	; Vowel
		y := x
	else if (SubStr(x, 1, 1) ~= "i)^[BFM]")	; BFM
		y := SubStr(x,2), BFM := true
	else
		y := SubStr(x,2)
	StringLower, y, y
	output := X ", " X ", bo-"	(SubStr(x,1,1)="b"&&BFM ? "" : "b") Y
	. "`nBanana-fana fo-"		(SubStr(x,1,1)="f"&&BFM ? "" : "f") Y
	. "`nFee-fi-mo-"		(SubStr(x,1,1)="m"&&BFM ? "" : "m") Y
	. "`n" X "!"
	result .= output "`n`n"
}
MsgBox, 262144, ,% result


# syntax: GAWK -f THE_NAME_GAME.AWK
BEGIN {
    n = split("gary,earl,billy,felix,mary,shirley",arr,",")
    for (i=1; i<=n; i++) {
      print_verse(arr[i])
    }
    exit(0)
}
function print_verse(name,  c,x,y) {
    x = toupper(substr(name,1,1)) tolower(substr(name,2))
    y = (x ~ /^[AEIOU]/) ? tolower(x) : substr(x,2)
    c = substr(x,1,1)
    printf("%s, %s, bo-%s%s\n",x,x,(c~/B/)?"":"b",y)
    printf("Banana-fana fo-%s%s\n",(c~/F/)?"":"f",y)
    printf("Fee-fi-mo-%s%s\n",(c~/M/)?"":"m",y)
    printf("%s!\n\n",x)
}


#!/bin/ksh
exec 2> /tmp/Top_rank_per_group.err

# Top rank per group

#	# Variables:
#
integer TOP_NUM=2

typeset -T Empsal_t=(
	typeset -h		'Employee Name'			ename=''
	typeset -h		'Employee ID'			eid=''
	typeset -i -h	'Employee Salary'		esalary
	typeset -h		'Emplyee Department'	edept=''

	function init_employee {
		typeset buff ; buff="$1"

		typeset oldIFS ; oldIFS="$IFS"
		typeset arr ; typeset -a arr
		IFS=\,
		arr=( ${buff} )

		_.ename="${arr[0]}"
		_.eid="${arr[1]}"
		_.esalary=${arr[2]}
		_.edept="${arr[3]}"

		IFS="${oldIFS}"
	}
)

edata='Tyler Bennett,E10297,32000,D101
John Rappl,E21437,47000,D050
George Woltman,E00127,53500,D101
Adam Smith,E63535,18000,D202
Claire Buckman,E39876,27800,D202
David McClellan,E04242,41500,D101
Rich Holcomb,E01234,49500,D202
Nathan Adams,E41298,21900,D050
Richard Potter,E43128,15900,D101
David Motsinger,E27002,19250,D202
Tim Sampair,E03033,27000,D101
Kim Arlich,E10001,57000,D190
Timothy Grove,E16398,29900,D190'

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

#	# Employee data into array of Types
#
typeset -a empsal_t		# array of Type variables (objects)
integer j i=0
echo "${edata}" | while read; do
	Empsal_t empsal_t[i]					# Create Type (object)
	empsal_t[i++].init_employee "$REPLY"	# Initialize Type (object)
done

#	# Sort the array of Type variables
#
set -a -s -A empsal_t -K edept,esalary:n:r,ename

#	# BUG work around! duplicate the now sorted Type array and use it for output
#
sorted=$(typeset -p empsal_t) && sorted=${sorted/empsal_t/sorted} && eval ${sorted}

for ((i=0; i<${#sorted[*]}; i++)); do
	if [[ ${sorted[i].edept} != ${prevdept} ]] || (( j < TOP_NUM )); then
		[[ ${sorted[i].edept} != ${prevdept} ]] && j=0
		print "${sorted[i].edept} ${sorted[i].esalary} ${sorted[i].eid} ${sorted[i].ename}"
		prevdept=${sorted[i].edept}
		(( j++ ))
	fi
done


subroutine TheGameName(nombre)
	x = lower(nombre)
	x = upper(mid(x,1,1)) + (mid(x,2,length(x)-1))
	x0 = upper(mid(x,1,1))

	if x0 = "A" or x0 = "e" or x0 = "I" or x0 = "O" or x0 = "U" then
		y = lower(x)
	else
		y = mid(x,2,length(x)-1)
	end If

	b = "b" + y
	f = "f" + y
	m = "m" + y

	begin case
		case x0 = "B"
			b = y
		case x0 = "F"
			f = y
		case x0 = "M"
			m = y
	end case

	print x + ", " + x + ", bo-" + b
	print "Banana-fana fo-" + f
	print "Fee-fi-mo-" + m
	print x + "!" + chr(10)
end subroutine

dim listanombres[5]
listanombres = {"Gary", "EARL", "billy", "FeLiX", "Mary", "ShirleY"}
for i = 0 to listanombres[?]-1
	call TheGameName(listanombres[i])
next i
end


#include <stdio.h>
#include <string.h>

void print_verse(const char *name) {
    char *x, *y;
    int b = 1, f = 1, m = 1, i = 1;

    /* ensure name is in title-case */
    x = strdup(name);
    x[0] = toupper(x[0]);
    for (; x[i]; ++i) x[i] = tolower(x[i]);

    if (strchr("AEIOU", x[0])) {
        y = strdup(x);
        y[0] = tolower(y[0]);
    }
    else {
        y = x + 1;
    }

    switch(x[0]) {
        case 'B': b = 0; break;
        case 'F': f = 0; break;
        case 'M': m = 0; break;
        default : break;
    }

    printf("%s, %s, bo-%s%s\n", x, x, (b) ? "b" : "", y);
    printf("Banana-fana fo-%s%s\n", (f) ? "f" : "", y);
    printf("Fee-fi-mo-%s%s\n", (m) ? "m" : "", y);
    printf("%s!\n\n", x);
}

int main() {
    int i;
    const char *names[6] = {"gARY", "Earl", "Billy", "Felix", "Mary", "sHIRley"};
    for (i = 0; i < 6; ++i) print_verse(names[i]);
    return 0;
}


using System;
using System.Collections.Generic;
using System.Text;

namespace TheNameGame {
    class Program {
        static void PrintVerse(string name) {
            StringBuilder sb = new StringBuilder(name.ToLower());
            sb[0] = Char.ToUpper(sb[0]);
            string x = sb.ToString();
            string y = "AEIOU".IndexOf(x[0]) > -1 ? x.ToLower() : x.Substring(1);
            string b = "b" + y;
            string f = "f" + y;
            string m = "m" + y;
            switch (x[0]) {
                case 'B':
                    b = y;
                    break;
                case 'F':
                    f = y;
                    break;
                case 'M':
                    m = y;
                    break;
            }
            Console.WriteLine("{0}, {0}, bo-{1}", x, b);
            Console.WriteLine("Banana-fana fo-{0}", f);
            Console.WriteLine("Fee-fi-mo-{0}", m);
            Console.WriteLine("{0}!", x);
            Console.WriteLine();
        }

        static void Main(string[] args) {
            List<string> nameList = new List<string>() { "Gary", "Earl", "Billy", "Felix", "Mary", "Steve" };
            nameList.ForEach(PrintVerse);
        }
    }
}


#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

static void printVerse(const std::string& name) {
    std::string x = name;
    std::transform(x.begin(), x.end(), x.begin(), ::tolower);
    x[0] = toupper(x[0]);

    std::string y;
    switch (x[0]) {
    case 'A':
    case 'E':
    case 'I':
    case 'O':
    case 'U':
        y = x;
        std::transform(y.begin(), y.end(), y.begin(), ::tolower);
        break;
    default:
        y = x.substr(1);
        break;
    }

    std::string b("b" + y);
    std::string f("f" + y);
    std::string m("m" + y);

    switch (x[0]) {
    case 'B':
        b = y;
        break;
    case 'F':
        f = y;
        break;
    case 'M':
        m = y;
        break;
    default:
        break;
    }

    printf("%s, %s, bo-%s\n", x.c_str(), x.c_str(), b.c_str());
    printf("Banana-fana fo-%s\n", f.c_str());
    printf("Fee-fi-mo-%s\n", m.c_str());
    printf("%s!\n\n", x.c_str());
}

int main() {
    using namespace std;

    vector<string> nameList{ "Gary", "Earl", "Billy", "Felix", "Mary", "Steve" };
    for (auto& name : nameList) {
        printVerse(name);
    }

    return 0;
}


Module Checkit {
      ' erase stack of values, so we can add data
      Flush
      Input "N=",N
      Enum Departments {D050,D101,D190,D202}

      \\ Inventory Department need unique keys
      Inventory Department
      \\ each item in this inventory should be an inventory too
      Class Empl {
            name$, id$, salary
            Class:
            Module Empl(.name$, .id$, .salary) {}
      }
      Data "Tyler Bennett","E10297",32000,D101
      Data "John Rappl","E21437",47000,D050
      Data "George Woltman","E00127",53500,D101
      Data "Adam Smith","E63535",18000,D202
      Data "Claire Buckman","E39876",27800,D202
      Data "David McClellan","E04242",41500,D101
      Data "Rich Holcomb","E01234",49500,D202
      Data "Nathan Adams","E41298",21900,D050
      Data "Richard Potter","E43128",15900,D101
      Data "David Motsinger","E27002",19250,D202
      Data "Tim Sampair","E03033",27000,D101
      Data "Kim Arlich","E10001",57000,D190
      Data "Timothy Grove","E16398",29900,D190
      Data ""
      Read name$
      While name$<>""  {
            Read id$, salary, dep
            Rem : Print name$, id$, salary, dep
            If Exist(Department, dep) Then {
                  z=Eval(Department)    ' get pointer to inventory
                  AppendOne()
            } Else {
                  z=queue
                  AppendDep()
                  AppendOne()
            }
            Read name$
      }
      Sort Department as number
      i=each(Department)
      \\ make depname as type of Departments
      depname=D050
      Print  "Dep.  Employee Name       Emp. ID Salary"
      While i {
            \\ when we pass a number to a enum variable
            \\ if the number exist, get that enum item else raise error
            depname=val(eval$(i, i^))
            \\ z is a pointer to inventory
            z=Eval(i)
            Sort descending z as number
            k=each(z,1,N)
            While k {
                  Empl=Eval(k)
                  For Empl {
                        \\ eval$(depname) return the name of enum variable (like D050)
                        Print Format$("{0:6}{1:20}{2:8}{3::-8}",Eval$(depname), .name$, .id$, .salary)
                  }
            }
      }
      Print "Done"
      Sub AppendDep()
            Append Department, dep:=z
      End Sub
      Sub AppendOne()
                  Append z, salary:=Empl(name$, id$, salary)
      End Sub
}
Checkit


1 rem name game
2 rem rosetta code
5 dim cn$(3),bl$(3,32):gosub 1000

10 print chr$(147);chr$(14);"Name Game":print
15 cn$(0)="":cn$(1)="b":cn$(2)="f":cn$(3)="m"
20 print chr$(147);chr$(14);"Name Game":print:input "Enter any name";n$
25 rem ensure first letter is lowercase
30 n$=chr$(asc(n$) and 95)+right$(n$,len(n$)-1)
35 rem check vowels
40 v$="aeiou":i$=left$(n$,1):v=0
45 for i=1 to 5:v=i$=mid$(v$,i,1):if not v then next i
50 if v then tn$=n$:goto 70
55 gosub 500
60 if bl then goto 70
65 tn$=right$(n$,len(n$)-1):gosub 600
70 rem capitalize first letter in name
75 n$=chr$(asc(n$) or 128)+right$(n$,len(n$)-1)
80 gosub 700
83 print:print "Again? (Y/N)"
85 get k$:if k$<>"y" and k$<>"n" then 85
90 if k$="y" then goto 10
95 end

500 rem check blends
510 bl=0:for g=3 to 1 step -1
520 l$=left$(n$,g+1):tn$=right$(n$,len(n$)-(g+1))
530 for i=1 to 32:if l$=bl$(g,i) then bl=-1:return
540 next i:next g
550 return

600 rem check b, f, and m
610 for i=1 to 3:if cn$(i)=chr$(asc(n$)) then cn$(i)=""
620 next i:return

700 rem sing the verse
710 print:print n$;", ";n$;", bo-";cn$(1);tn$
720 print "   Banana-fana fo-";cn$(2);tn$
730 print "   Fee-fi-mo-";cn$(3);tn$
740 print n$;"!"
750 return

1000 rem load blends
1010 for g=1 to 3
1015 for i=1 to 32
1020 read bl$(g,i):if bl$(g,i)="xx" then next g:return
1030 next i

2000 rem digraphs
2005 data bl,br,ch,ck,cl,cr,dr,fl,fr,gh,gl,gr,ng
2010 data ph,pl,pr,qu,sc,sh,sk,sl,sm,sn,sp,st,sw
2020 data th,tr,tw,wh,wr
2029 data xx
2030 rem trigraphs
2040 data chr,sch,scr,shr,spl,spr,squ,str,thr
2049 data xx
2050 rem quadgraph
2060 data schr,schl
2069 data xx


import std.algorithm;
import std.array;
import std.conv;
import std.stdio;
import std.uni;

void printVerse(string name) {
    auto sb = name.map!toLower.array;
    sb[0] = sb[0].toUpper;

    string x = sb.to!string;
    string y;
    switch(sb[0]) {
        case 'A':
        case 'E':
        case 'I':
        case 'O':
        case 'U':
            y = x.map!toLower.to!string;
            break;
        default:
            y = x[1..$];
            break;
    }
    string b = "b" ~ y;
    string f = "f" ~ y;
    string m = "m" ~ y;
    switch (x[0]) {
        case 'B':
            b = y;
            break;
        case 'F':
            f = y;
            break;
        case 'M':
            m = y;
            break;
        default:
            // no adjustment needed
            break;
    }

    writeln(x, ", ", x, ", bo-", b);
    writeln("Banana-fana fo-", f);
    writeln("Fee-fi-mo-", m);
    writeln(x, "!\n");
}

void main() {
    foreach (name; ["Gary","Earl","Billy","Felix","Mary","steve"]) {
        printVerse(name);
    }
}


func printVerse(name) {
    let x = name[..1].Upper() + name[1..].Lower();
    let y = "AEIOU".IndexOf(x[0]) > -1 ? x.Lower() : x[1..]
    let b = x[0] is 'B' ? y : "b" + y
    let f = x[0] is 'F' ? y : "f" + y
    let m = x[0] is 'M' ? y : "m" + y

    print("\(x), \(x), bo-\(b)")
    print("Banana-fana fo-\(f)")
    print("Fee-fi-mo-\(m)")
    print("\(x)!", x)
    print()
}

let seq = yields { "Gary", "Earl", "Billy", "Felix", "Mary", "Steve" }

for x in seq {
    printVerse(x)
}


import algorithm

type Record = tuple[name, id: string; salary: int; department: string]

var people = [("Tyler Bennett", "E10297", 32000, "D101"),
              ("John Rappl", "E21437", 47000, "D050"),
              ("George Woltman", "E00127", 53500, "D101"),
              ("Adam Smith", "E63535", 18000, "D202"),
              ("Claire Buckman", "E39876", 27800, "D202"),
              ("David McClellan", "E04242", 41500, "D101"),
              ("Rich Holcomb", "E01234", 49500, "D202"),
              ("Nathan Adams", "E41298", 21900, "D050"),
              ("Richard Potter", "E43128", 15900, "D101"),
              ("David Motsinger", "E27002", 19250, "D202"),
              ("Tim Sampair", "E03033", 27000, "D101"),
              ("Kim Arlich", "E10001", 57000, "D190"),
              ("Timothy Grove", "E16398", 29900, "D190")]

proc pcmp(a, b: Record): int =
  result = cmp(a.department, b.department)
  if result == 0:
    result = cmp(b.salary, a.salary)

proc printTop(people: openArray[Record]; n: Positive) =
  var people = sorted(people, pcmp)
  var rank = 0
  for i, p in people:
    if i > 0 and p.department != people[i-1].department:
      rank = 0
      echo()
    if rank < n:
      echo p.department, " ", p.salary, " ", p.name
    inc rank

people.printTop(2)


USING: ascii combinators interpolate io kernel locals
pair-rocket qw sequences ;
IN: rosetta-code.name-game

: vowel? ( char -- ? ) "AEIOU" member? ;

:: name-game ( Name -- )

    Name first  :> L
    Name >lower :> name! L vowel? [ name rest name! ] unless
    "b"         :> B!
    "f"         :> F!
    "m"         :> M!

    L { CHAR: B => [ "" B! ]
        CHAR: F => [ "" F! ]
        CHAR: M => [ "" M! ] [ drop ] } case

[I ${Name}, ${Name}, bo-${B}${name}
Banana-fana fo-${F}${name}
Fee-fi-mo-${M}${name}
${Name}!I] nl nl ;

qw{ Gary Earl Billy Felix Milton Steve } [ name-game ] each