Top rank per group
From Rosetta Code
You are encouraged to solve this task according to the task description, using any language you may know.
Use this data as a formatted internal data structure (adapt it to your language-native idioms, rather than parse at runtime), or identify your external data source:
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
Contents |
[edit] AutoHotkey
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 deptment
;---------------------------------------------------------------------------
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
}
Message boxes show:
Department: D050 --------------------------- John Rappl E21437 47000 D050 Nathan Adams E41298 21900 D050
Department: D101 --------------------------- George Woltman E00127 53500 D101 David McClellan E04242 41500 D101 Tyler Bennett E10297 32000 D101
Department: D190 --------------------------- Kim Arlich E10001 57000 D190 Timothy Grove E16398 29900 D190
Department: D202 --------------------------- Rich Holcomb E01234 49500 D202 Claire Buckman E39876 27800 D202 David Motsinger E27002 19250 D202
[edit] C++
#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;
}
Output:
In department D050 Name ID Salary Department John Rappl E21437 47000 D050 Nathan Adams E41298 21900 D050 In department D101 Name ID Salary Department George Woltman E21437 53500 D101 David McClellan E04242 41500 D101 Tyler Bennett E10297 32000 D101 In department D190 Name ID Salary Department Kim Arlich E10001 57000 D190 Timothy Grove E16398 29900 D190 In department D202 Name ID Salary Department Rich Holcomb E01234 49500 D202 Claire Buckman E39876 27800 D202 David Motsinger E27002 19250 D202
[edit] C#
using System;
using System.Collections.Generic;
using System.Linq;
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;
public string ID;
public int Salary;
public string Department;
}
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")
};
var rankedGroups = from e in Employees
orderby e.Department, e.Salary descending
group e by e.Department into g
select new { Dept = g.Key, EmpDetails = g };
foreach (var group in rankedGroups)
{
Console.WriteLine("Department {0,-11}\r\n---------------", group.Dept);
Console.WriteLine(" Name ID Salary Department\r\n --------------- ------ ------ ----------");
foreach (Employee e in group.EmpDetails)
Console.WriteLine(" {0, -15} {1} {2} {3}", e.Name, e.ID, e.Salary, e.Department);
Console.WriteLine();
}
}
}
Output:
Department D050 --------------- Name ID Salary Department --------------- ------ ------ ---------- John Rappl E21437 47000 D050 Nathan Adams E41298 21900 D050 Department D101 --------------- Name ID Salary Department --------------- ------ ------ ---------- George Woltman E21437 53500 D101 David McClellan E04242 41500 D101 Tyler Bennett E10297 32000 D101 Tim Sampair E03033 27000 D101 Richard Potter E43128 15900 D101 Department D190 --------------- Name ID Salary Department --------------- ------ ------ ---------- Kim Arlich E10001 57000 D190 Timothy Grove E16398 29900 D190 Department D202 --------------- Name ID Salary Department --------------- ------ ------ ---------- Rich Holcomb E01234 49500 D202 Claire Buckman E39876 27800 D202 David Motsinger E27002 19250 D202 Adam Smith E21437 18000 D202
[edit] Clojure
(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)))
Output:
Department: D050
{:Name John Rappl, :ID E21437, :Salary 47000, :Department D050}
{:Name Nathan Adams, :ID E41298, :Salary 21900, :Department D050}
Department: D101
{:Name George Woltman, :ID E00127, :Salary 53500, :Department D101}
{:Name David McClellan, :ID E04242, :Salary 41500, :Department D101}
{:Name Tyler Bennett, :ID E10297, :Salary 32000, :Department D101}
Department: D190
{:Name Kim Arlich, :ID E10001, :Salary 57000, :Department D190}
{:Name Timothy Grove, :ID E16398, :Salary 29900, :Department D190}
Department: D202
{:Name Rich Holcomb, :ID E01234, :Salary 49500, :Department D202}
{:Name Claire Buckman, :ID E39876, :Salary 27800, :Department D202}
{:Name David Motsinger, :ID E27002, :Salary 19250, :Department D202}
[edit] Common Lisp
(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)))))
Example
> (defparameter *employee-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))
"A list of lists of each employee's name, id, salary, and
department.")
*EMPLOYEE-DATA*
> (top-n-by-group 3 *employee-data* 'third 'fourth '>)
#<EQL Hash Table{4} 2361A0E7>
> (describe *)
#<EQL Hash Table{4} 2361A0E7> is a HASH-TABLE
D101 (3 (("Tyler Bennett" E10297 32000 D101) ("David McClellan" E04242 41500 D101) ("George Woltman" E00127 53500 D101)))
D050 (2 (("Nathan Adams" E41298 21900 D050) ("John Rappl" E21437 47000 D050)))
D202 (3 (("David Motsinger" E27002 19250 D202) ("Claire Buckman" E39876 27800 D202) ("Rich Holcomb" E01234 49500 D202)))
D190 (2 (("Timothy Grove" E16398 29900 D190) ("Kim Arlich" E10001 57000 D190)))
[edit] 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()
}
}
(Note: This uses an append-and-then-sort to maintain the list of top N; a sorted insert or a proper selection algorithm would be more efficient. As long as N is small, this does not matter much; the algorithm is O(n) with respect to the data set.)
? topSalaries(3, stdout)
Department D050
---------------
E21437 $47000 John Rappl
E41298 $21900 Nathan Adams
Department D101
---------------
E00127 $53500 George Woltman
E04242 $41500 David McClellan
E10297 $32000 Tyler Bennett
Department D190
---------------
E10001 $57000 Kim Arlich
E16398 $29900 Timothy Grove
Department D202
---------------
E01234 $49500 Rich Holcomb
E39876 $27800 Claire Buckman
E27002 $19250 David Motsinger
[edit] F#
let 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";
]
let topRank n =
Seq.groupBy (fun (_, _, _, d) -> d) data
|> Seq.map (snd >> Seq.sortBy (fun (_, _, s, _) -> -s) >> Seq.take n)
[edit] Factor
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 ;
Output:
Department D101: E00127 $53500 George Woltman E04242 $41500 David McClellan E10297 $32000 Tyler Bennett Department D202: E01234 $49500 Rich Holcomb E39876 $27800 Claire Buckman E27002 $19250 David Motsinger Department D190: E10001 $57000 Kim Arlich E16398 $29900 Timothy Grove Department D050: E21437 $47000 John Rappl E41298 $21900 Nathan Adams
[edit] Haskell
import Data.List
import Control.Monad
import Control.Arrow
import Text.Printf
import Data.Ord
import Data.Function
groupingOn = ((==) `on`)
comparingDwn = flip . comparing
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 = map (\(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)
]
dorank :: Int ->
(Employee -> DEP) ->
(Employee -> SALARY) ->
[Employee]-> [[Employee]]
dorank n o1 o2 = map (take n. sortBy (comparingDwn o2))
. groupBy (groupingOn o1) . sortBy (comparing o1)
toprank :: IO ()
toprank = do
printf "%-16s %3s %10s\n" "NAME" "DEP" "TIP"
putStrLn $ replicate 31 '='
mapM_ (mapM_ (ap (ap (printf "%-16s %3s %10.2g\n" . name) dep) sal)) $ dorank 3 dep sal employees
Output: top 3 per department
*Main> toprank NAME DEP TIP =============================== de Bont C.A. AB 65000.00 Anders H. AB 50000.00 de Slegte S. AB 46987.00 Uitlaat G.A.S. CC 44500.00 de Goeij J. CC 39000.00 Zagt A. CC 33000.00 Telmans R.M. CD 55500.00 Janszen H.P. CD 41000.00 Janszoon A. CD 38665.00 Ezelbips P.J. KA 52000.00 't Woud B. KA 45000.00 Pragtweik J.M.V. KA 42300.00
[edit] HicEst
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
John Rappl E21437 47000 D050 Nathan Adams E41298 21900 D050 George Woltman E00127 53500 D101 David McClellan E04242 41500 D101 Tyler Bennett E10297 32000 D101 Kim Arlich E10001 57000 D190 Timothy Grove E16398 29900 D190 Rich Holcomb E01234 49500 D202 Claire Buckman E39876 27800 D202 David Motsinger E27002 19250 D202
Note: In place of writing the sorted result to file outP, DLG allows the direct export of the formatted and sorted result. Use of the CLUSter= and Groups= options of SORT performs a variance controlled cluster sort of up to 8 columns instead of the department step sort in this example.
[edit] J
J has a rich set of primitive functions, which combine the power of an imperative language with the expressiveness of a declarative, SQL-like language:
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
+-----+-----+-----------------+------+ |ID |DEPT |NAME |SALARY| +-----+-----+-----------------+------+ |1013 |AB |de Bont C.A. |65000 | |1203 |AB |Anders H. |50000 | |1093 |AB |de Slegte S. |46987 | |1001 |AB |Janssen A.H. |41000 | +-----+-----+-----------------+------+ |100 |KA |Ezelbips P.J. |52000 | |101 |KA |'t Woud B. |45000 | |106 |KA |Pragtweik J.M.V. |42300 | |105 |KA |Clubdrager C. |39800 | |119 |KA |Tegenstroom H.L. |39000 | |107 |KA |Centjes R.M. |34000 | +-----+-----+-----------------+------+ |1199 |CC |Uitlaat G.A.S. |44500 | |1011 |CC |de Goeij J. |39000 | |1102 |CC |Zagt A. |33000 | |1107 |CC |Beloop L.O. |31000 | |1101 |CC |Modaal A.M.J. |30000 | |1106 |CC |Boon T.J. |25000 | +-----+-----+-----------------+------+ |1111 |CD |Telmans R.M. |55500 | |1026 |CD |Janszen H.P. |41000 | |1009 |CD |Janszoon A. |38665 | +-----+-----+-----------------+------+
using the data set:
Employees=: (<;.1~(1 1{.~#);+./@:(;:E.S:0])@:{.)];._2 noun define
ID DEPT NAME SALARY
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
)
Named as a function where the (maximum) number of employees in each department is a parameter:
reportTopSalaries=: 3 :'N , (<@:>"1@:|:@:((y <. #) {. ] \: SALARY)/.~ DEPT) |: <"1&> E'
Example of use:
reportTopSalaries 2 +-----+-----+-----------------+------+ |ID |DEPT |NAME |SALARY| +-----+-----+-----------------+------+ |1013 |AB |de Bont C.A. |65000 | |1203 |AB |Anders H. |50000 | +-----+-----+-----------------+------+ |100 |KA |Ezelbips P.J. |52000 | |101 |KA |'t Woud B. |45000 | +-----+-----+-----------------+------+ |1199 |CC |Uitlaat G.A.S. |44500 | |1011 |CC |de Goeij J. |39000 | +-----+-----+-----------------+------+ |1111 |CD |Telmans R.M. |55500 | |1026 |CD |Janszen H.P. |41000 | +-----+-----+-----------------+------+
[edit] JavaScript
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 balary
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);
outputs:
D101 George Woltman, id=E00127, salary=53500 David McClellan, id=E04242, salary=41500 Tyler Bennett, id=E10297, salary=32000 D050 John Rappl, id=E21437, salary=47000 Nathan Adams, id=E41298, salary=21900 D202 Rich Holcomb, id=E01234, salary=49500 Claire Buckman, id=E39876, salary=27800 David Motsinger, id=E27002, salary=19250 D190 Kim Arlich, id=E10001, salary=57000 Timothy Grove, id=E16398, salary=29900
[edit] OCaml
open StdLabels
let to_string (name,_,s,_) = (Printf.sprintf "%s (%d)" name s)
let take n li =
let rec aux i acc = function
| _ when i >= n -> (List.rev acc)
| [] -> (List.rev acc)
| x::xs -> aux (succ i) (x::acc) xs
in
aux 0 [] li ;;
let toprank data n =
let len = List.length data in
let h = Hashtbl.create len in
List.iter data ~f:(fun ((_,_,_,dep) as employee) ->
Hashtbl.add h dep employee);
let deps =
List.fold_left data ~init:[] ~f:
(fun ac (_,_,_,v) -> if List.mem v ac then ac else v::ac) in
let f dep =
Printf.printf "Department: %s\n " dep;
let l = Hashtbl.find_all h dep in
let l2 = List.sort (fun (_,_,v1,_) (_,_,v2,_) -> compare v2 v1) l in
let l3 = (take n l2) in
print_endline(String.concat ", " (List.map to_string l3));
print_newline()
in
List.iter f deps;
;;
let 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";
]
let () =
toprank data 3;
;;
outputs:
Department: D190 Kim Arlich (57000), Timothy Grove (29900) Department: D202 Rich Holcomb (49500), Claire Buckman (27800), David Motsinger (19250) Department: D050 John Rappl (47000), Nathan Adams (21900) Department: D101 George Woltman (53500), David McClellan (41500), Tyler Bennett (32000)
[edit] Oz
declare
%% Create a list of employee records.
Data = {Map
[['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]]
fun {$ [Name Id Salary Department]}
employee(name:Name id:Id salary:Salary department:Department)
end}
fun {TopEarners Employees N}
{Record.map {GroupBy Employees department}
fun {$ Employees}
{List.take
{Sort Employees CompareSalary}
N}
end}
end
fun {CompareSalary E1 E2}
E1.salary > E2.salary
end
%% Groups the records Xs by the value of feature F and returns
%% the result as a record that maps values of F to list of records.
fun {GroupBy Xs F}
Groups = {Dictionary.new}
in
for X in Xs do
Groups.(X.F) := X|{CondSelect Groups X.F nil}
end
{Dictionary.toRecord unit Groups}
end
in
{Inspect {TopEarners Data 3}}
[edit] Perl
sub zip {
my @a = @{shift()};
my @b = @{shift()};
my @l;
push @l, shift @a, shift @b while @a and @b;
return @l;
}
sub uniq {
my %h;
grep {!$h{$_}++} @_;
}
my @data =
map {{ zip [qw(name id salary dept)], [split ','] }}
split "\n",
<<'EOF';
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
EOF
@ARGV or die "Please provide a value for N.\n";
my $N = shift;
foreach my $d (sort uniq map {$_->{dept}} @data) {
print "$d\n";
my @es =
sort {$b->{salary} <=> $a->{salary}}
grep {$_->{dept} eq $d}
@data;
foreach (1 .. $N) {
@es or last;
my $e = shift @es;
printf "%-15s | %-6s | %5d\n", @{$e}{qw(name id salary)};
}
print "\n";
}
[edit] PHP
$data = Array(
Array("Tyler Bennett","E10297",32000,"D101"),
Array("John Rappl","E21437",47000,"D050"),
Array("George Woltman","E00127",53500,"D101"),
Array("Adam Smith","E63535",18000,"D202"),
Array("Claire Buckman","E39876",27800,"D202"),
Array("David McClellan","E04242",41500,"D101"),
Array("Rich Holcomb","E01234",49500,"D202"),
Array("Nathan Adams","E41298",21900,"D050"),
Array("Richard Potter","E43128",15900,"D101"),
Array("David Motsinger","E27002",19250,"D202"),
Array("Tim Sampair","E03033",27000,"D101"),
Array("Kim Arlich","E10001",57000,"D190"),
Array("Timothy Grove","E16398",29900,"D190")
);
function top_sal($num){
global $data;
$depts = Array();
foreach($data as $key => $arr){
if(!isset($depts[$arr[3]])) $depts[$arr[3]] = Array();
$depts[$arr[3]][] = $key;
}
function topsalsort($a,$b){
global $data;
if ($data[$a][2] == $data[$b][2]) {
return 0;
}
return ($data[$a][2] < $data[$b][2]) ? 1 : -1;
}
foreach ($depts as $key => $val){
usort($depts[$key],"topsalsort");
}
ksort($depts);
echo '<pre>';
foreach ($depts as $key => $val){
echo $key . '<br>';
echo 'Name ID Salary<br>';
$count = 0;
foreach($val as $value){
echo $data[$value][0] . ' ' . $data[$value][1] . ' ' . $data[$value][2] . '<br>';
$count++;
if($count>=$num) break;
}
echo '<br>';
}
echo '</pre>';
}
top_sal(3);
D050 Name ID Salary John Rappl E21437 47000 Nathan Adams E41298 21900 D101 Name ID Salary George Woltman E00127 53500 David McClellan E04242 41500 Tyler Bennett E10297 32000 D190 Name ID Salary Kim Arlich E10001 57000 Timothy Grove E16398 29900 D202 Name ID Salary Rich Holcomb E01234 49500 Claire Buckman E39876 27800 David Motsinger E27002 19250
[edit] PicoLisp
# Employee Name, ID, Salary, Department
(de *Employees
("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) )
(de topEmployees (N)
(let Fmt (4 -16 -7 7)
(for Dept (by cadddr group *Employees)
(prinl "Department " (cadddr (car Dept)) ":")
(tab Fmt NIL "Name" "ID" "Salary")
(for (I . D) (flip (by caddr sort Dept))
(tab Fmt (pack I ". ") (car D) (cadr D) (caddr D))
(T (= I N)) )
(prinl) ) ) )
(topEmployees 3)
Output:
Department D101:
Name ID Salary
1. George Woltman E00127 53500
2. David McClellan E04242 41500
3. Tyler Bennett E10297 32000
Department D050:
Name ID Salary
1. John Rappl E21437 47000
2. Nathan Adams E41298 21900
Department D202:
Name ID Salary
1. Rich Holcomb E01234 49500
2. Claire Buckman E39876 27800
3. David Motsinger E27002 19250
Department D190:
Name ID Salary
1. Kim Arlich E10001 57000
2. Timothy Grove E16398 29900
[edit] PowerShell
function New-Employee ($Name, $ID, $Salary, $Department) {
New-Object PSObject `
| Add-Member -PassThru NoteProperty EmployeeName $Name `
| Add-Member -PassThru NoteProperty EmployeeID $ID `
| Add-Member -PassThru NoteProperty Salary $Salary `
| Add-Member -PassThru NoteProperty Department $Department
}
$data = (New-Employee 'Tyler Bennett' E10297 32000 D101),
(New-Employee 'John Rappl' E21437 47000 D050),
(New-Employee 'George Woltman' E00127 53500 D101),
(New-Employee 'Adam Smith' E63535 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)
function Get-TopRank ($n) {
$data `
| Group-Object Department `
| ForEach-Object {
$_.Group `
| Sort-Object Salary -Descending `
| Select-Object -First $n
} `
| Format-Table -GroupBy Department
}
Output:
PS> Get-TopRank 2 Department: D101 EmployeeName EmployeeID Salary Department ------------ ---------- ------ ---------- George Woltman E00127 53500 D101 David McClellan E04242 41500 D101 Department: D050 EmployeeName EmployeeID Salary Department ------------ ---------- ------ ---------- John Rappl E21437 47000 D050 Nathan Adams E41298 21900 D050 Department: D202 EmployeeName EmployeeID Salary Department ------------ ---------- ------ ---------- Rich Holcomb E01234 49500 D202 Claire Buckman E39876 27800 D202 Department: D190 EmployeeName EmployeeID Salary Department ------------ ---------- ------ ---------- Kim Arlich E10001 57000 D190 Timothy Grove E16398 29900 D190
[edit] PureBasic
Structure Employees
Name$
ID$
Salary.i
Department$
EndStructure
Procedure displayTopEarners(List MyEmployees.Employees(), n)
Protected filename$ = OpenFileRequester("Top rank per group", "DataFile.txt", "", 0)
If ReadFile(0, filename$)
Protected InData.Employees, txt.s, MaxNameLength
While Eof(0) = 0
AddElement(MyEmployees())
txt = ReadString(0)
With MyEmployees()
\Name$ = StringField(txt, 1, ",")
\ID$ = StringField(txt, 2, ",")
\Salary = Val(StringField(txt, 3, ","))
\Department$ = StringField(txt, 4, ",")
If Len(\Name$) > MaxNameLength: MaxNameLength = Len(\Name$): EndIf
EndWith
Wend
CloseFile(0)
Else
MessageRequester("Information", "Couldn't open the file!")
End
EndIf
If OpenConsole()
Protected OldDepartment$, count
SortStructuredList(MyEmployees(), #PB_Sort_Descending, OffsetOf(Employees\Salary), #PB_Sort_integer)
SortStructuredList(MyEmployees(), #PB_Sort_Ascending, OffsetOf(Employees\Department$), #PB_Sort_String)
ForEach MyEmployees()
With MyEmployees()
If \Department$ <> OldDepartment$
If OldDepartment$ <> ""
PrintN(#CRLF$)
EndIf
OldDepartment$ = \Department$
PrintN("Department " + \Department$ + #CRLF$ + "---------------")
PrintN(LSet("Name", MaxNameLength + 3) + LSet("ID", 7) + LSet("Salary", 7))
count = 0
EndIf
count + 1
If count <= n
PrintN(LSet(\Name$, MaxNameLength + 1) + " " + RSet(\ID$, 7) + " $" + Str(\Salary))
EndIf
EndWith
Next
PrintN(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
EndIf
EndProcedure
NewList MyEmployees.Employees()
displayTopEarners(MyEmployees(), 3)
Save this as 'DataFile.txt and let the program open this file
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
Ouput from the program looks like
Department D050 --------------- Name ID Salary John Rappl E21437 $47000 Nathan Adams E41298 $21900 Department D101 --------------- Name ID Salary George Woltman E00127 $53500 David McClellan E04242 $41500 Tyler Bennett E10297 $32000 Department D190 --------------- Name ID Salary Kim Arlich E10001 $57000 Timothy Grove E16398 $29900 Department D202 --------------- Name ID Salary Rich Holcomb E01234 $49500 Claire Buckman E39876 $27800 David Motsinger E27002 $19250 Press ENTER to exit
[edit] Python
from collections import defaultdictOutput:
from heapq import nlargest
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')]
departments = defaultdict(list)
for rec in data[1:]:
departments[rec[-1]].append(rec)
N = 3
format = "%-15s " * len(data[0])
for department, recs in departments.iteritems():
print "Department", department
print " ", format % data[0]
for rec in nlargest(N, recs, key=lambda rec: rec[-2]):
print " ", format % rec
Department D101 Employee Name Employee ID Salary Department George Woltman E00127 53500 D101 David McClellan E04242 41500 D101 Tyler Bennett E10297 32000 D101 Department D202 Employee Name Employee ID Salary Department Rich Holcomb E01234 49500 D202 Claire Buckman E39876 27800 D202 David Motsinger E27002 19250 D202 Department D190 Employee Name Employee ID Salary Department Kim Arlich E10001 57000 D190 Timothy Grove E16398 29900 D190 Department D050 Employee Name Employee ID Salary Department John Rappl E21437 47000 D050 Nathan Adams E41298 21900 D050
Alternative Solution
Uses namedtuples for database records, and groupby builtin to group records by Department:
from collections import namedtuple
from itertools import groupby
N = 2
db = '''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'''
rows = db.split('\n')
DBRecord = namedtuple('DBRecord', rows[0].replace(' ', '_'))
records = [ DBRecord(*row.split(',')) for row in rows[1:] ]
records.sort(key = lambda record: (record.Department, -float(record.Salary)))
print '\n\n'.join('\n '.join([dpt] + [str(g) for g in grp][:N])
for dpt, grp in groupby(records,
lambda record: record.Department))
Sample output
D050 DBRecord(Employee_Name='John Rappl', Employee_ID='E21437', Salary='47000', Department='D050') DBRecord(Employee_Name='Nathan Adams', Employee_ID='E41298', Salary='21900', Department='D050') D101 DBRecord(Employee_Name='George Woltman', Employee_ID='E00127', Salary='53500', Department='D101') DBRecord(Employee_Name='David McClellan', Employee_ID='E04242', Salary='41500', Department='D101') D190 DBRecord(Employee_Name='Kim Arlich', Employee_ID='E10001', Salary='57000', Department='D190') DBRecord(Employee_Name='Timothy Grove', Employee_ID='E16398', Salary='29900', Department='D190') D202 DBRecord(Employee_Name='Rich Holcomb', Employee_ID='E01234', Salary='49500', Department='D202') DBRecord(Employee_Name='Claire Buckman', Employee_ID='E39876', Salary='27800', Department='D202')
[edit] R
First, read in the data.
dfr <- read.csv(tc <- textConnection(
"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")); close(tc)
To just return the top salary, it's very simple using tapply.
with(dfr, tapply(Salary, Department, max))
To return N salaries, we replace max with our own function.
get.top.N.salaries <- function(N)
{
with(dfr, tapply(Salary, Department,
function(x)
{
sort(x);
lx <- length(x)
if(N >= lx) return(x)
x[-1:(N-lx)]
}))
}
get.top.N.salaries(3)
$D050 [1] 47000 21900 $D101 [1] 41500 15900 27000 $D190 [1] 57000 29900 $D202 [1] 27800 49500 19250
To return the whole record for each of the top salaries, a different tack is required.
get.top.N.salaries2 <- function(N)
{
#Sort data frame by Department, then by Salary
sorted <- dfr[with(dfr, order(Department, Salary, decreasing=TRUE)),]
#Split the dataframe up, by Department
bydept <- split(sorted, sorted$Department)
#Return the first N values (or all of them
lapply(bydept,
function(x)
{
n <- min(N, nrow(x))
x[1:n,]
})
}
get.top.N.salaries2(3)
$D050
Employee.Name Employee.ID Salary Department
2 John Rappl E21437 47000 D050
8 Nathan Adams E41298 21900 D050
$D101
Employee.Name Employee.ID Salary Department
3 George Woltman E00127 53500 D101
6 David McClellan E04242 41500 D101
1 Tyler Bennett E10297 32000 D101
$D190
Employee.Name Employee.ID Salary Department
12 Kim Arlich E10001 57000 D190
13 Timothy Grove E16398 29900 D190
$D202
Employee.Name Employee.ID Salary Department
7 Rich Holcomb E01234 49500 D202
5 Claire Buckman E39876 27800 D202
10 David Motsinger E27002 19250 D202
[edit] Ruby
Without much thought to report formatting: Works with: Ruby version 1.8.7+
Employee = Struct.new(:name, :employee_id, :salary, :department)
def get_employees
[
Employee.new("Tyler Bennett", "E10297", 32000, "D101"),
Employee.new("John Rappl", "E21437", 47000, "D050"),
Employee.new("George Woltman", "E00127", 53500, "D101"),
Employee.new("Adam Smith", "E63535", 18000, "D202"),
Employee.new("Claire Buckman", "E39876", 27800, "D202"),
Employee.new("David McClellan", "E04242", 41500, "D101"),
Employee.new("Rich Holcomb", "E01234", 49500, "D202"),
Employee.new("Nathan Adams", "E41298", 21900, "D050"),
Employee.new("Richard Potter", "E43128", 15900, "D101"),
Employee.new("David Motsinger", "E27002", 19250, "D202"),
Employee.new("Tim Sampair", "E03033", 27000, "D101"),
Employee.new("Kim Arlich", "E10001", 57000, "D190"),
Employee.new("Timothy Grove", "E16398", 29900, "D190"),
]
end
def show_top_salaries_per_group(groups, n)
groups.each do |dept, emps|
puts dept
# sort by salary descending
emps.sort_by {|emp| -emp.salary}[0,n].each {|e| p e}
puts
end
end
groups = get_employees.group_by {|emp| emp.department}
show_top_salaries_per_group(groups,3)
D101 #<struct Employee name="George Woltman", employee_id="E00127", salary=53500, department="D101"> #<struct Employee name="David McClellan", employee_id="E04242", salary=41500, department="D101"> #<struct Employee name="Tyler Bennett", employee_id="E10297", salary=32000, department="D101"> D190 #<struct Employee name="Kim Arlich", employee_id="E10001", salary=57000, department="D190"> #<struct Employee name="Timothy Grove", employee_id="E16398", salary=29900, department="D190"> D202 #<struct Employee name="Rich Holcomb", employee_id="E01234", salary=49500, department="D202"> #<struct Employee name="Claire Buckman", employee_id="E39876", salary=27800, department="D202"> #<struct Employee name="David Motsinger", employee_id="E27002", salary=19250, department="D202"> D050 #<struct Employee name="John Rappl", employee_id="E21437", salary=47000, department="D050"> #<struct Employee name="Nathan Adams", employee_id="E41298", salary=21900, department="D050">
[edit] Scala
object TopRank extends Application {
import scala.io._
val 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"""
class Employee(val name:String, val id:String, val salary:Int, val department:String) {
override def toString = id +"\t"+salary+"\t"+name
}
Source.fromString(data).getLines().map(_.split(",")).map(x => new Employee(x(0), x(1), x(2).toInt, x(3) )).toList // read data into list of employees
.sortBy(x => (x.department, -x.salary)).groupBy(_.department).foreach{ group => // sort and group by
println("Department: "+group._1)
group._2.take(3).foreach{x => println("\t"+x) }
}
}
output:
Department: D050 E21437 47000 John Rappl E41298 21900 Nathan Adams Department: D101 E00127 53500 George Woltman E04242 41500 David McClellan E10297 32000 Tyler Bennett Department: D190 E10001 57000 Kim Arlich E16398 29900 Timothy Grove Department: D202 E01234 49500 Rich Holcomb E39876 27800 Claire Buckman E27002 19250 David Motsinger
[edit] SMEQL
The following SMEQL example returns the top 6 earners in each department based on this table schema:
table: Employees
----------------
empID
dept
empName
salary
Source Code:
srt = orderBy(Employees, (dept, salary), order)
top = group(srt, [(dept) dept2, max(order) order])
join(srt, top, a.dept=b.dept2 and b.order - a.order < 6)
[edit] Tcl
Works with: Tcl version 8.5
package require Tcl 8.5
set text {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}
set data [dict create]
foreach line [split $text \n] {
lassign [split $line ,] name id salary dept
dict lappend data $dept [list $name $id $salary]
}
proc top_n_salaries {n data} {
incr n -1
dict for {dept employees} $data {
puts "Department $dept"
foreach emp [lrange [lsort -integer -decreasing -index 2 $employees] 0 $n] {
puts [format " %-20s %-8s %8d" {*}$emp]
}
puts ""
}
}
top_n_salaries 3 $data
outputs
Department D101 George Woltman E00127 53500 David McClellan E04242 41500 Tyler Bennett E10297 32000 Department D050 John Rappl E21437 47000 Nathan Adams E41298 21900 Department D202 Rich Holcomb E01234 49500 Claire Buckman E39876 27800 David Motsinger E27002 19250 Department D190 Kim Arlich E10001 57000 Timothy Grove E16398 29900
[edit] Ursala
The algorithm used by the top function is to lex the data into fields, partition by the last field, sort each partition descending by the second to last, take the first n strings in each partition, and display the list of them in a reasonably understandable form.
#import std
#import nat
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]-
top "n" = @tt sep`,*; mat0+ ^C(~&hz,mat`,*yS)*+ take/*"n"+ *zK2 (nleq+ %np~~)-<x&yzNC
#show+
main = top3 data
output:
D190 Kim Arlich,E10001,57000 Timothy Grove,E16398,29900 D101 George Woltman,E00127,53500 David McClellan,E04242,41500 Tyler Bennett,E10297,32000 D202 Rich Holcomb,E01234,49500 Claire Buckman,E39876,27800 David Motsinger,E27002,19250 D050 John Rappl,E21437,47000 Nathan Adams,E41298,21900

