Sort an array of composite structures: Difference between revisions
added Ursala |
|||
(174 intermediate revisions by 97 users not shown) | |||
Line 1: | Line 1: | ||
{{task|Sorting}} |
{{task|Sorting Algorithms}} |
||
{{Sorting Algorithm}} |
|||
Sort an array of composite structures by a key. For example, if you define a composite structure that presents a name-value pair (in pseudocode): |
|||
[[Category:Sorting]] |
|||
Sort an array of composite structures by a key. |
|||
For example, if you define a composite structure that presents a name-value pair (in pseudo-code): |
|||
Define structure pair such that: |
Define structure pair such that: |
||
Line 8: | Line 14: | ||
and an array of such pairs: |
and an array of such pairs: |
||
x: array of pairs |
|||
then define a sort routine that sorts the array ''x'' by the key ''name''. |
then define a sort routine that sorts the array ''x'' by the key ''name''. |
||
This task can always be accomplished with [[Sorting Using a Custom Comparator]]. |
This task can always be accomplished with [[Sorting Using a Custom Comparator]]. |
||
If your language is not listed here, please see the other article. |
|||
<br><br> |
|||
=={{header|11l}}== |
|||
{{trans|Kotlin}} |
|||
<syntaxhighlight lang="11l">T Employee |
|||
String name, category |
|||
F (name, category) |
|||
.name = name |
|||
.category = category |
|||
V employees = [ |
|||
Employee(‘David’, ‘Manager’), |
|||
Employee(‘Alice’, ‘Sales’), |
|||
Employee(‘Joanna’, ‘Director’), |
|||
Employee(‘Henry’, ‘Admin’), |
|||
Employee(‘Tim’, ‘Sales’), |
|||
Employee(‘Juan’, ‘Admin’) |
|||
] |
|||
employees.sort(key' e -> e.name) |
|||
L(e) employees |
|||
print(‘#<6 : #.’.format(e.name, e.category))</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Alice : Sales |
|||
David : Manager |
|||
Henry : Admin |
|||
Joanna : Director |
|||
Juan : Admin |
|||
Tim : Sales |
|||
</pre> |
|||
=={{header|AArch64 Assembly}}== |
|||
{{works with|as|Raspberry Pi 3B version Buster 64 bits}} |
|||
<syntaxhighlight lang="aarch64 assembly"> |
|||
/* ARM assembly AARCH64 Raspberry PI 3B */ |
|||
/* program shellSort64.s */ |
|||
/*******************************************/ |
|||
/* Constantes file */ |
|||
/*******************************************/ |
|||
/* for this file see task include a file in language AArch64 assembly*/ |
|||
.include "../includeConstantesARM64.inc" |
|||
/*******************************************/ |
|||
/* Structures */ |
|||
/********************************************/ |
|||
/* city structure */ |
|||
.struct 0 |
|||
city_name: // |
|||
.struct city_name + 8 // string pointer |
|||
city_habitants: // |
|||
.struct city_habitants + 8 // integer |
|||
city_end: |
|||
/*********************************/ |
|||
/* Initialized data */ |
|||
/*********************************/ |
|||
.data |
|||
sMessResult: .asciz "Name : @ number habitants : @ \n" |
|||
szMessSortHab: .asciz "Sort table for number of habitants :\n" |
|||
szMessSortName: .asciz "Sort table for name of city :\n" |
|||
szCarriageReturn: .asciz "\n" |
|||
// cities name |
|||
szCeret: .asciz "Ceret" |
|||
szMaureillas: .asciz "Maureillas" |
|||
szTaillet: .asciz "Taillet" |
|||
szReynes: .asciz "Reynes" |
|||
szVives: .asciz "Vivés" |
|||
szBoulou: .asciz "Le Boulou" |
|||
szSaintJean: .asciz "Saint Jean Pla de Corts" |
|||
szCluses: .asciz "Les Cluses" |
|||
szAlbere: .asciz "L'Albère" |
|||
szPerthus: .asciz "Le Perthus" |
|||
.align 4 |
|||
TableCities: |
|||
.quad szCluses // address name string |
|||
.quad 251 // number of habitants |
|||
.quad szCeret |
|||
.quad 7705 |
|||
.quad szMaureillas |
|||
.quad 2596 |
|||
.quad szBoulou |
|||
.quad 5554 |
|||
.quad szSaintJean |
|||
.quad 2153 |
|||
.quad szAlbere |
|||
.quad 83 |
|||
.quad szVives |
|||
.quad 174 |
|||
.quad szTaillet |
|||
.quad 115 |
|||
.quad szPerthus |
|||
.quad 586 |
|||
.quad szReynes |
|||
.quad 1354 |
|||
.equ NBELEMENTS, (. - TableCities) / city_end |
|||
.skip city_end // temp area for element in shellSort |
|||
// see other soluce to use stack |
|||
// in programm arm assembly in this forum |
|||
/*********************************/ |
|||
/* UnInitialized data */ |
|||
/*********************************/ |
|||
.bss |
|||
sZoneConv: .skip 24 |
|||
/*********************************/ |
|||
/* code section */ |
|||
/*********************************/ |
|||
.text |
|||
.global main |
|||
main: // entry of program |
|||
ldr x0,qAdrszMessSortHab |
|||
bl affichageMess |
|||
ldr x0,qAdrTableCities // address table |
|||
mov x1,0 // not use in routine |
|||
mov x2,NBELEMENTS // number of élements |
|||
mov x3,#city_habitants // sort by number habitants |
|||
mov x4,#'N' // numeric |
|||
bl shellSort |
|||
ldr x0,qAdrTableCities // address table |
|||
bl displayTable |
|||
ldr x0,qAdrszMessSortName |
|||
bl affichageMess |
|||
ldr x0,qAdrTableCities // address table |
|||
mov x1,0 // not use in routine |
|||
mov x2,NBELEMENTS // number of élements |
|||
mov x3,#city_name // sort by city name |
|||
mov x4,#'A' // alphanumeric |
|||
bl shellSort |
|||
ldr x0,qAdrTableCities // address table |
|||
bl displayTable |
|||
100: // standard end of the program |
|||
mov x0,0 // return code |
|||
mov x8,EXIT // request to exit program |
|||
svc 0 // perform the system call |
|||
qAdrsZoneConv: .quad sZoneConv |
|||
qAdrszCarriageReturn: .quad szCarriageReturn |
|||
qAdrsMessResult: .quad sMessResult |
|||
qAdrTableCities: .quad TableCities |
|||
qAdrszMessSortHab: .quad szMessSortHab |
|||
qAdrszMessSortName: .quad szMessSortName |
|||
/***************************************************/ |
|||
/* shell Sort */ |
|||
/***************************************************/ |
|||
/* x0 contains the address of table */ |
|||
/* x1 contains the first element but not use !! */ |
|||
/* this routine use first element at index zero !!! */ |
|||
/* x2 contains the number of element */ |
|||
/* x3 contains the offset of sort zone */ |
|||
/* x4 contains type of sort zone N = numeric A = alphanumeric */ |
|||
shellSort: |
|||
stp x1,lr,[sp,-16]! // save registers |
|||
stp x2,x3,[sp,-16]! // save registers |
|||
stp x4,x5,[sp,-16]! // save registers |
|||
stp x6,x7,[sp,-16]! // save registers |
|||
stp x8,x9,[sp,-16]! // save registers |
|||
stp x10,x11,[sp,-16]! // save registers |
|||
stp x12,x13,[sp,-16]! // save registers |
|||
mov x8,x3 // save offset area sort |
|||
mov x9,x4 // save type sort |
|||
mov x7,city_end // element size |
|||
sub x12,x2,1 // index last item |
|||
mov x11,x12 // init gap = last item |
|||
1: // start loop 1 |
|||
lsr x11,x11,1 // gap = gap / 2 |
|||
cbz x11,100f // if gap = 0 -> end |
|||
mov x3,x11 // init loop indice 1 |
|||
2: // start loop 2 |
|||
mul x1,x3,x7 // offset élement |
|||
mov x2,NBELEMENTS |
|||
mul x2,x7,x2 |
|||
bl copyElement |
|||
add x1,x1,x8 // + offset sort zone |
|||
ldr x4,[x0,x1] // load first value |
|||
mov x5,x3 // init loop indice 2 |
|||
3: // start loop 3 |
|||
cmp x5,x11 // indice < gap |
|||
blt 7f // yes -> end loop 2 |
|||
sub x6,x5,x11 // index = indice - gap |
|||
mul x1,x6,x7 // compute offset |
|||
add x10,x1,x8 // + offset sort zone |
|||
ldr x2,[x0,x10] // load second value |
|||
cmp x9,#'A' // sort area alapha ? |
|||
beq 4f // yes |
|||
cmp x4,x2 // else compare numeric values |
|||
bge 7f // highter |
|||
b 6f // lower |
|||
4: // compare area alphanumeric |
|||
mov x10,#0 // counter |
|||
5: |
|||
ldrb w13,[x4,x10] // byte string 1 |
|||
ldrb w6,[x2,x10] // byte string 2 |
|||
cmp w13,w6 |
|||
bgt 7f |
|||
blt 6f |
|||
cmp w13,#0 // end string 1 |
|||
beq 7f // end comparaison |
|||
add x10,x10,#1 // else add 1 in counter |
|||
b 5b // and loop |
|||
6: |
|||
mul x2,x5,x7 // offset élement |
|||
bl copyElement // copy element x1 to element x2 |
|||
sub x5,x5,x11 // indice = indice - gap |
|||
b 3b // and loop |
|||
7: |
|||
mov x1,NBELEMENTS |
|||
mul x1,x7,x1 |
|||
mul x2,x7,x5 |
|||
bl copyElement |
|||
add x3,x3,1 // increment indice 1 |
|||
cmp x3,x12 // end ? |
|||
ble 2b // no -> loop 2 |
|||
b 1b // yes loop for new gap |
|||
100: // end function |
|||
ldp x12,x13,[sp],16 // restaur 2 registers |
|||
ldp x10,x11,[sp],16 // restaur 2 registers |
|||
ldp x8,x9,[sp],16 // restaur 2 registers |
|||
ldp x6,x7,[sp],16 // restaur 2 registers |
|||
ldp x4,x5,[sp],16 // restaur 2 registers |
|||
ldp x2,x3,[sp],16 // restaur 2 registers |
|||
ldp x1,lr,[sp],16 // restaur 2 registers |
|||
ret // return to address lr x30 |
|||
/******************************************************************/ |
|||
/* copy table element */ |
|||
/******************************************************************/ |
|||
/* r0 contains the address of table */ |
|||
/* r1 offset origin element */ |
|||
/* r2 offset destination element */ |
|||
copyElement: |
|||
stp x1,lr,[sp,-16]! // save registers |
|||
stp x2,x3,[sp,-16]! // save registers |
|||
stp x4,x5,[sp,-16]! // save registers |
|||
mov x3,0 |
|||
add x1,x1,x0 |
|||
add x2,x2,x0 |
|||
1: |
|||
ldrb w4,[x1,x3] |
|||
strb w4,[x2,x3] |
|||
add x3,x3,1 |
|||
cmp x3,city_end |
|||
blt 1b |
|||
100: |
|||
ldp x4,x5,[sp],16 // restaur 2 registers |
|||
ldp x2,x3,[sp],16 // restaur 2 registers |
|||
ldp x1,lr,[sp],16 // restaur 2 registers |
|||
ret // return to address lr x30 |
|||
/******************************************************************/ |
|||
/* Display table elements */ |
|||
/******************************************************************/ |
|||
/* x0 contains the address of table */ |
|||
displayTable: |
|||
stp x1,lr,[sp,-16]! // save registers |
|||
stp x2,x3,[sp,-16]! // save registers |
|||
stp x4,x5,[sp,-16]! // save registers |
|||
stp x6,x7,[sp,-16]! // save registers |
|||
mov x2,x0 // table address |
|||
mov x3,0 |
|||
mov x6,city_end |
|||
1: // loop display table |
|||
mul x4,x3,x6 |
|||
add x4,x4,city_name |
|||
ldr x1,[x2,x4] |
|||
ldr x0,qAdrsMessResult |
|||
bl strInsertAtCharInc // put name in message |
|||
mov x5,x0 // save address of new message |
|||
mul x4,x3,x6 |
|||
add x4,x4,city_habitants // and load value |
|||
ldr x0,[x2,x4] |
|||
ldr x1,qAdrsZoneConv // display value |
|||
bl conversion10 // call function |
|||
mov x0,x5 |
|||
ldr x1,qAdrsZoneConv |
|||
bl strInsertAtCharInc // insert result at @ character |
|||
bl affichageMess // display message |
|||
add x3,x3,1 |
|||
cmp x3,#NBELEMENTS - 1 |
|||
ble 1b |
|||
ldr x0,qAdrszCarriageReturn |
|||
bl affichageMess |
|||
100: |
|||
ldp x6,x7,[sp],16 // restaur 2 registers |
|||
ldp x4,x5,[sp],16 // restaur 2 registers |
|||
ldp x2,x3,[sp],16 // restaur 2 registers |
|||
ldp x1,lr,[sp],16 // restaur 2 registers |
|||
ret // return to address lr x30 |
|||
/********************************************************/ |
|||
/* File Include fonctions */ |
|||
/********************************************************/ |
|||
/* for this file see task include a file in language AArch64 assembly */ |
|||
.include "../includeARM64.inc" |
|||
</syntaxhighlight> |
|||
<pre> |
|||
Sort table for number of habitants : |
|||
Name : L'Albère number habitants : 83 |
|||
Name : Taillet number habitants : 115 |
|||
Name : Vivés number habitants : 174 |
|||
Name : Les Cluses number habitants : 251 |
|||
Name : Le Perthus number habitants : 586 |
|||
Name : Reynes number habitants : 1354 |
|||
Name : Saint Jean Pla de Corts number habitants : 2153 |
|||
Name : Maureillas number habitants : 2596 |
|||
Name : Le Boulou number habitants : 5554 |
|||
Name : Ceret number habitants : 7705 |
|||
Sort table for name of city : |
|||
Name : Ceret number habitants : 7705 |
|||
Name : L'Albère number habitants : 83 |
|||
Name : Le Boulou number habitants : 5554 |
|||
Name : Le Perthus number habitants : 586 |
|||
Name : Les Cluses number habitants : 251 |
|||
Name : Maureillas number habitants : 2596 |
|||
Name : Reynes number habitants : 1354 |
|||
Name : Saint Jean Pla de Corts number habitants : 2153 |
|||
Name : Taillet number habitants : 115 |
|||
Name : Vivés number habitants : 174 |
|||
</pre> |
|||
=={{header|ACL2}}== |
|||
<syntaxhighlight lang="lisp">(defun insert-by-key (o os key) |
|||
(cond ((endp os) (list o)) |
|||
((< (cdr (assoc key o)) |
|||
(cdr (assoc key (first os)))) |
|||
(cons o os)) |
|||
(t (cons (first os) |
|||
(insert-by-key o (rest os) key))))) |
|||
(defun isort-by-key (os key) |
|||
(if (endp os) |
|||
nil |
|||
(insert-by-key (first os) |
|||
(isort-by-key (rest os) key) |
|||
key))) |
|||
(isort-by-key |
|||
'(((name . "map") |
|||
(weight . 9) |
|||
(value . 150)) |
|||
((name . "compass") |
|||
(weight . 13) |
|||
(value . 35)) |
|||
((name . "water") |
|||
(weight . 153) |
|||
(value . 200)) |
|||
((name . "sandwich") |
|||
(weight . 50) |
|||
(value . 60)) |
|||
((name . "glucose") |
|||
(weight . 15) |
|||
(value . 60))) |
|||
'value)</syntaxhighlight> |
|||
Output: |
|||
<pre>(((NAME . "compass") |
|||
(WEIGHT . 13) |
|||
(VALUE . 35)) |
|||
((NAME . "glucose") |
|||
(WEIGHT . 15) |
|||
(VALUE . 60)) |
|||
((NAME . "sandwich") |
|||
(WEIGHT . 50) |
|||
(VALUE . 60)) |
|||
((NAME . "map") |
|||
(WEIGHT . 9) |
|||
(VALUE . 150)) |
|||
((NAME . "water") |
|||
(WEIGHT . 153) |
|||
(VALUE . 200)))</pre> |
|||
=={{header|Action!}}== |
|||
<syntaxhighlight lang="action!">DEFINE PTR="CARD" |
|||
DEFINE PAIR_SIZE="4" |
|||
DEFINE PAIR_COUNT="1" |
|||
TYPE Pair=[PTR name,value] |
|||
BYTE ARRAY pairs(100) |
|||
BYTE count=[0] |
|||
PTR FUNC GetItemAddr(INT index) |
|||
PTR addr |
|||
addr=pairs+index*PAIR_SIZE |
|||
RETURN (addr) |
|||
PROC PrintArray() |
|||
INT i |
|||
Pair POINTER p |
|||
Put('[) |
|||
FOR i=0 TO count-1 |
|||
DO |
|||
IF i>0 THEN Put(' ) FI |
|||
p=GetItemAddr(i) |
|||
PrintF("(%S,%S)",p.name,p.value) |
|||
OD |
|||
Put(']) PutE() |
|||
RETURN |
|||
PROC Append(CHAR ARRAY n,v) |
|||
Pair POINTER dst |
|||
dst=GetItemAddr(count) |
|||
dst.name=n |
|||
dst.value=v |
|||
count==+1 |
|||
RETURN |
|||
PROC InitData() |
|||
Append("Warsaw","Poland") |
|||
Append("Prague","Czech Republic") |
|||
Append("London","United Kingdom") |
|||
Append("Paris","France") |
|||
Append("Madrit","Spain") |
|||
Append("Berlin","Germany") |
|||
Append("Rome","Italy") |
|||
Append("Moscow","Russia") |
|||
Append("Budapest","Hungary") |
|||
RETURN |
|||
PROC Sort() |
|||
INT i,j,minpos |
|||
CHAR ARRAY tmp |
|||
Pair POINTER p1,p2 |
|||
FOR i=0 TO count-2 |
|||
DO |
|||
minpos=i |
|||
FOR j=i+1 TO count-1 |
|||
DO |
|||
p1=GetItemAddr(minpos) |
|||
p2=GetItemAddr(j) |
|||
IF SCompare(p1.name,p2.name)>0 THEN |
|||
minpos=j |
|||
FI |
|||
OD |
|||
IF minpos#i THEN |
|||
p1=GetItemAddr(minpos) |
|||
p2=GetItemAddr(i) |
|||
tmp=p1.name p1.name=p2.name p2.name=tmp |
|||
tmp=p1.value p1.value=p2.value p2.value=tmp |
|||
FI |
|||
OD |
|||
RETURN |
|||
PROC Main() |
|||
InitData() |
|||
PrintE("Array before sort:") |
|||
PrintArray() PutE() |
|||
Sort() |
|||
PrintE("Array after sort:") |
|||
PrintArray() |
|||
RETURN</syntaxhighlight> |
|||
{{out}} |
|||
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Sort_an_array_of_composite_structures.png Screenshot from Atari 8-bit computer] |
|||
<pre> |
|||
Array before sort: |
|||
[(Warsaw,Poland) (Prague,Czech Republic) (London,United Kingdom) (Paris,France) (Madrit,Spain) (Berlin,Germany) (Rome,Italy) (Moscow,Russia) (Budapest,Hungary)] |
|||
Array after sort: |
|||
[(Berlin,Germany) (Budapest,Hungary) (London,United Kingdom) (Madrit,Spain) (Moscow,Russia) (Paris,France) (Prague,Czech Republic) (Rome,Italy) (Warsaw,Poland)] |
|||
</pre> |
|||
=={{header|Ada}}== |
=={{header|Ada}}== |
||
[[Ada 2005]] defines 2 standard subprograms for sorting arrays - 1 for constrained arrays and 1 for unconstrained arrays. Below is a example of using the unconstrained version. |
[[Ada 2005]] defines 2 standard subprograms for sorting arrays - 1 for constrained arrays and 1 for unconstrained arrays. Below is a example of using the unconstrained version. |
||
<syntaxhighlight lang="ada">with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; |
|||
<lang ada> |
|||
with Ada.Text_IO; use Ada.Text_IO; |
|||
with Ada.Text_IO; use Ada.Text_IO; |
|||
with Ada.Containers.Generic_Array_Sort; |
|||
with Ada.Containers.Generic_Array_Sort; |
|||
procedure Demo_Array_Sort is |
|||
procedure Demo_Array_Sort is |
|||
function "+" (S : String) return Unbounded_String renames To_Unbounded_String; |
|||
function "+" (S : String) return Unbounded_String renames To_Unbounded_String; |
|||
type A_Composite is |
|||
record |
|||
Name : Unbounded_String; |
|||
Value : Unbounded_String; |
|||
end record; |
|||
end record; |
|||
function "<" (L, R : A_Composite) return Boolean is |
|||
begin |
|||
function "<" (L, R : A_Composite) return Boolean is |
|||
return L.Name < R.Name; |
|||
begin |
|||
end "<"; |
|||
return L.Name < R.Name; |
|||
end "<"; |
|||
procedure Put_Line (C : A_Composite) is |
|||
begin |
|||
procedure Put_Line (C : A_Composite) is |
|||
Put_Line (To_String (C.Name) & " " & To_String (C.Value)); |
|||
begin |
|||
end Put_Line; |
|||
Put_Line (To_String (C.Name) & " " & To_String (C.Value)); |
|||
end Put_Line; |
|||
type An_Array is array (Natural range <>) of A_Composite; |
|||
type An_Array is array (Natural range <>) of A_Composite; |
|||
procedure Sort is new Ada.Containers.Generic_Array_Sort (Natural, A_Composite, An_Array); |
|||
procedure Sort is new Ada.Containers.Generic_Array_Sort (Natural, A_Composite, An_Array); |
|||
Data : An_Array := (1 => (Name => +"Joe", Value => +"5531"), |
|||
2 => (Name => +"Adam", Value => +"2341"), |
|||
3 => (Name => +"Bernie", Value => +"122"), |
|||
4 => (Name => +"Walter", Value => +"1234"), |
|||
5 => (Name => +"David", Value => +"19")); |
|||
5 => (Name => +"David", Value => +"19")); |
|||
begin |
|||
Sort (Data); |
|||
begin |
|||
for I in Data'Range loop |
|||
Put_Line (Data (I)); |
|||
end loop; |
|||
Put_Line (Data (I)); |
|||
end Demo_Array_Sort;</syntaxhighlight> |
|||
end loop; |
|||
end Demo_Array_Sort; |
|||
</lang> |
|||
Result: |
Result: |
||
<pre> |
<pre> |
||
Line 69: | Line 553: | ||
</pre> |
</pre> |
||
[[Ada 2005]] also provides ordered containers, so no explicit call is required. Here is an example of an ordered set: |
[[Ada 2005]] also provides ordered containers, so no explicit call is required. Here is an example of an ordered set: |
||
<syntaxhighlight lang="ada">with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; |
|||
<lang ada> |
|||
with Ada.Text_IO; use Ada.Text_IO; |
|||
with Ada.Text_IO; use Ada.Text_IO; |
|||
with Ada.Containers.Ordered_Sets; |
|||
with Ada.Containers.Ordered_Sets; |
|||
procedure Sort_Composites is |
|||
procedure Sort_Composites is |
|||
function "+" (S : String) return Unbounded_String renames To_Unbounded_String; |
|||
function "+" (S : String) return Unbounded_String renames To_Unbounded_String; |
|||
type A_Composite is |
|||
record |
|||
Name : Unbounded_String; |
|||
Value : Unbounded_String; |
|||
end record; |
|||
end record; |
|||
function "<" (L, R : A_Composite) return Boolean is |
|||
begin |
|||
function "<" (L, R : A_Composite) return Boolean is |
|||
return L.Name < R.Name; |
|||
begin |
|||
end "<"; |
|||
return L.Name < R.Name; |
|||
end "<"; |
|||
procedure Put_Line (C : A_Composite) is |
|||
begin |
|||
procedure Put_Line (C : A_Composite) is |
|||
Put_Line (To_String (C.Name) & " " & To_String (C.Value)); |
|||
begin |
|||
end Put_Line; |
|||
Put_Line (To_String (C.Name) & " " & To_String (C.Value)); |
|||
end Put_Line; |
|||
package Composite_Sets is new Ada.Containers.Ordered_Sets (A_Composite); |
|||
package Composite_Sets is new Ada.Containers.Ordered_Sets (A_Composite); |
|||
procedure Put_Line (C : Composite_Sets.Cursor) is |
|||
begin |
|||
procedure Put_Line (C : Composite_Sets.Cursor) is |
|||
Put_Line (Composite_Sets.Element (C)); |
|||
begin |
|||
end Put_Line; |
|||
end Put_Line; |
|||
Data : Composite_Sets.Set; |
|||
Data : Composite_Sets.Set; |
|||
begin |
|||
Data.Insert (New_Item => (Name => +"Joe", Value => +"5531")); |
|||
begin |
|||
Data.Insert (New_Item => (Name => +"Adam", Value => +"2341")); |
|||
Data.Insert (New_Item => (Name => +"Bernie", Value => +"122")); |
|||
Data.Insert (New_Item => (Name => +"Walter", Value => +"1234")); |
|||
Data.Insert (New_Item => (Name => +"David", Value => +"19")); |
|||
Data.Iterate (Put_Line'Access); |
|||
Data.Insert (New_Item => (Name => +"David", Value => +"19")); |
|||
end Sort_Composites;</syntaxhighlight> |
|||
Data.Iterate (Put_Line'Access); |
|||
end Sort_Composites; |
|||
</lang> |
|||
Result: |
Result: |
||
<pre> |
<pre> |
||
Line 123: | Line 605: | ||
</pre> |
</pre> |
||
There is no standard sort function for [[Ada 95]]. The example below implements a simple bubble sort. |
There is no standard sort function for [[Ada 95]]. The example below implements a simple bubble sort. |
||
<syntaxhighlight lang="ada">with Ada.Text_Io; |
|||
<lang ada> |
|||
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; |
|||
with Ada.Text_Io; |
|||
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; |
|||
procedure Sort_Composite is |
|||
type Composite_Record is record |
|||
procedure Sort_Composite is |
|||
Name : Unbounded_String; |
|||
type Composite_Record is record |
|||
Value : Unbounded_String; |
|||
end record; |
|||
Value : Unbounded_String; |
|||
end record; |
|||
type Pairs_Array is array(Positive range <>) of Composite_Record; |
|||
type Pairs_Array is array(Positive range <>) of Composite_Record; |
|||
procedure Swap(Left, Right : in out Composite_Record) is |
|||
Temp : Composite_Record := Left; |
|||
begin |
|||
Temp : Composite_Record := Left; |
|||
Left := Right; |
|||
begin |
|||
Right := Temp; |
|||
end Swap; |
|||
Right := Temp; |
|||
-- Sort_Names uses a bubble sort |
|||
-- Sort_Names uses a bubble sort |
|||
procedure Sort_Name(Pairs : in out Pairs_Array) is |
|||
Swap_Performed : Boolean := True; |
|||
procedure Sort_Name(Pairs : in out Pairs_Array) is |
|||
begin |
|||
Swap_Performed : Boolean := True; |
|||
while Swap_Performed loop |
|||
begin |
|||
Swap_Performed := False; |
|||
for I in Pairs'First..(Pairs'Last - 1) loop |
|||
Swap_Performed := False; |
|||
if Pairs(I).Name > Pairs(I + 1).Name then |
|||
Swap (Pairs(I), Pairs(I + 1)); |
|||
Swap_Performed := True; |
|||
end if; |
|||
end loop; |
|||
end loop; |
|||
end Sort_Name; |
|||
end Sort_Name; |
|||
procedure Print(Item : Pairs_Array) is |
|||
begin |
|||
procedure Print(Item : Pairs_Array) is |
|||
for I in Item'range loop |
|||
begin |
|||
Ada.Text_Io.Put_Line(To_String(Item(I).Name) & ", " & |
|||
for I in Item'range loop |
|||
to_String(Item(I).Value)); |
|||
end loop; |
|||
to_String(Item(I).Value)); |
|||
end Print; |
|||
type Names is (Fred, Barney, Wilma, Betty, Pebbles); |
|||
end Print; |
|||
type Values is (Home, Work, Cook, Eat, Bowl); |
|||
My_Pairs : Pairs_Array(1..5); |
|||
type Values is (Home, Work, Cook, Eat, Bowl); |
|||
begin |
|||
My_Pairs : Pairs_Array(1..5); |
|||
for I in My_Pairs'range loop |
|||
begin |
|||
My_Pairs(I).Name := To_Unbounded_String(Names'Image(Names'Val(Integer(I - 1)))); |
|||
for I in My_Pairs'range loop |
|||
My_Pairs(I).Value := To_Unbounded_String(Values'Image(Values'Val(Integer(I - 1)))); |
|||
end loop; |
|||
My_Pairs(I).Value := To_Unbounded_String(Values'Image(Values'Val(Integer(I - 1)))); |
|||
Print(My_Pairs); |
|||
Ada.Text_Io.Put_Line("========================="); |
|||
Print(My_Pairs); |
|||
Sort_Name(My_Pairs); |
|||
Ada.Text_Io.Put_Line("========================="); |
|||
Print(My_Pairs); |
|||
end Sort_Composite;</syntaxhighlight> |
|||
Print(My_Pairs); |
|||
end Sort_Composite; |
|||
</lang> |
|||
=={{header|ALGOL 68}}== |
=={{header|ALGOL 68}}== |
||
{{trans|python}} |
{{trans|python}} |
||
Line 185: | Line 666: | ||
{{works with|ALGOL 68G|Any - tested with release mk15-0.8b.fc9.i386}} |
{{works with|ALGOL 68G|Any - tested with release mk15-0.8b.fc9.i386}} |
||
<!-- {{does not work with|ELLA ALGOL 68|Any (with appropriate job cards AND formatted transput statements removed) - tested with release 1.8.8d.fc9.i386 - ELLA has no FORMATted transput}} --> |
<!-- {{does not work with|ELLA ALGOL 68|Any (with appropriate job cards AND formatted transput statements removed) - tested with release 1.8.8d.fc9.i386 - ELLA has no FORMATted transput}} --> |
||
< |
<syntaxhighlight lang="algol68">MODE SORTSTRUCT = PERSON; |
||
OP < = (PERSON a,b)BOOL: age OF a < age OF b; |
OP < = (PERSON a,b)BOOL: age OF a < age OF b; |
||
PR READ "prelude/sort.a68" PR; |
PR READ "prelude/sort.a68" PR; |
||
Line 193: | Line 674: | ||
[]SORTSTRUCT person = (("joe", 120), ("foo", 31), ("bar", 51)); |
[]SORTSTRUCT person = (("joe", 120), ("foo", 31), ("bar", 51)); |
||
printf((person repr, shell sort(person), $l$))</ |
printf((person repr, shell sort(person), $l$))</syntaxhighlight> |
||
Output: |
Output: |
||
<pre> |
<pre> |
||
Line 200: | Line 681: | ||
Name: joe, Age: 120 |
Name: joe, Age: 120 |
||
</pre> |
</pre> |
||
=={{header|AppleScript}}== |
|||
macOS Yosemite onwards, for import of Foundation framework |
|||
<syntaxhighlight lang="applescript">use framework "Foundation" |
|||
----- SORTING COMPOSITE STRUCTURES (BY MULTIPLE KEYS) ------ |
|||
-- List of {strKey, blnAscending} pairs -> list of records -> sorted list of records |
|||
-- sortByComparing :: [(String, Bool)] -> [Record] -> [Record] |
|||
on sortByComparing(keyDirections, xs) |
|||
set ca to current application |
|||
script recDict |
|||
on |λ|(x) |
|||
ca's NSDictionary's dictionaryWithDictionary:x |
|||
end |λ| |
|||
end script |
|||
set dcts to map(recDict, xs) |
|||
script asDescriptor |
|||
on |λ|(kd) |
|||
set {k, d} to kd |
|||
ca's NSSortDescriptor's sortDescriptorWithKey:k ascending:d selector:dcts |
|||
end |λ| |
|||
end script |
|||
((ca's NSArray's arrayWithArray:dcts)'s ¬ |
|||
sortedArrayUsingDescriptors:map(asDescriptor, keyDirections)) as list |
|||
end sortByComparing |
|||
--------------------------- TEST --------------------------- |
|||
on run |
|||
set xs to [¬ |
|||
{city:"Shanghai ", pop:24.2}, ¬ |
|||
{city:"Karachi ", pop:23.5}, ¬ |
|||
{city:"Beijing ", pop:21.5}, ¬ |
|||
{city:"Sao Paulo ", pop:24.2}, ¬ |
|||
{city:"Dhaka ", pop:17.0}, ¬ |
|||
{city:"Delhi ", pop:16.8}, ¬ |
|||
{city:"Lagos ", pop:16.1}] |
|||
-- Boolean true for ascending order, false for descending: |
|||
sortByComparing([{"pop", false}, {"city", true}], xs) |
|||
end run |
|||
-------------------- GENERIC FUNCTIONS --------------------- |
|||
-- map :: (a -> b) -> [a] -> [b] |
|||
on map(f, xs) |
|||
tell mReturn(f) |
|||
set lng to length of xs |
|||
set lst to {} |
|||
repeat with i from 1 to lng |
|||
set end of lst to |λ|(item i of xs, i, xs) |
|||
end repeat |
|||
return lst |
|||
end tell |
|||
end map |
|||
-- Lift 2nd class handler function into 1st class script wrapper |
|||
-- mReturn :: Handler -> Script |
|||
on mReturn(f) |
|||
if class of f is script then |
|||
f |
|||
else |
|||
script |
|||
property |λ| : f |
|||
end script |
|||
end if |
|||
end mReturn</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>{{pop:24.2, city:"Sao Paulo "}, {pop:24.2, city:"Shanghai "}, {pop:23.5, city:"Karachi "}, {pop:21.5, city:"Beijing "}, {pop:17.0, city:"Dhaka "}, {pop:16.8, city:"Delhi "}, {pop:16.1, city:"Lagos "}}</pre> |
|||
=={{header|ARM Assembly}}== |
|||
{{works with|as|Raspberry Pi}} |
|||
<syntaxhighlight lang="arm assembly"> |
|||
/* ARM assembly Raspberry PI */ |
|||
/* program compositeSort.s */ |
|||
/* REMARK 1 : this program use routines in a include file |
|||
see task Include a file language arm assembly |
|||
for the routine affichageMess conversion10 |
|||
see at end of this program the instruction include */ |
|||
/* for constantes see task include a file in arm assembly */ |
|||
/************************************/ |
|||
/* Constantes */ |
|||
/************************************/ |
|||
.include "../constantes.inc" |
|||
/*******************************************/ |
|||
/* Structures */ |
|||
/********************************************/ |
|||
/* city structure */ |
|||
.struct 0 |
|||
city_name: @ |
|||
.struct city_name + 4 |
|||
city_habitants: @ |
|||
.struct city_habitants + 4 |
|||
city_end: |
|||
/*********************************/ |
|||
/* Initialized data */ |
|||
/*********************************/ |
|||
.data |
|||
sMessResult: .asciz "Name : @ number habitants : @ \n" |
|||
szMessSortHab: .asciz "Sort table for number of habitants :\n" |
|||
szMessSortName: .asciz "Sort table for name of city :\n" |
|||
szCarriageReturn: .asciz "\n" |
|||
// cities name |
|||
szCeret: .asciz "Ceret" |
|||
szMaureillas: .asciz "Maureillas" |
|||
szTaillet: .asciz "Taillet" |
|||
szReynes: .asciz "Reynes" |
|||
szVives: .asciz "Vivés" |
|||
szBoulou: .asciz "Le Boulou" |
|||
szSaintJean: .asciz "Saint Jean Pla de Corts" |
|||
szCluses: .asciz "Les Cluses" |
|||
szAlbere: .asciz "L'Albère" |
|||
szPerthus: .asciz "Le Perthus" |
|||
.align 4 |
|||
TableCities: |
|||
.int szCluses @ address name string |
|||
.int 251 @ number of habitants |
|||
.int szCeret |
|||
.int 7705 |
|||
.int szMaureillas |
|||
.int 2596 |
|||
.int szBoulou |
|||
.int 5554 |
|||
.int szSaintJean |
|||
.int 2153 |
|||
.int szAlbere |
|||
.int 83 |
|||
.int szVives |
|||
.int 174 |
|||
.int szTaillet |
|||
.int 115 |
|||
.int szPerthus |
|||
.int 586 |
|||
.int szReynes |
|||
.int 1354 |
|||
.equ NBELEMENTS, (. - TableCities) / city_end |
|||
/*********************************/ |
|||
/* UnInitialized data */ |
|||
/*********************************/ |
|||
.bss |
|||
sZoneConv: .skip 24 |
|||
/*********************************/ |
|||
/* code section */ |
|||
/*********************************/ |
|||
.text |
|||
.global main |
|||
main: @ entry of program |
|||
ldr r0,iAdrszMessSortHab |
|||
bl affichageMess |
|||
ldr r0,iAdrTableCities @ address city table |
|||
mov r1,#0 @ not use in routine |
|||
mov r2,#NBELEMENTS @ number of élements |
|||
mov r3,#city_habitants @ sort by number habitants |
|||
mov r4,#'N' @ Alphanumeric |
|||
bl shellSort |
|||
ldr r0,iAdrTableCities @ address number table |
|||
bl displayTable |
|||
ldr r0,iAdrszMessSortName |
|||
bl affichageMess |
|||
ldr r0,iAdrTableCities @ address city table |
|||
mov r1,#0 @ not use in routine |
|||
mov r2,#NBELEMENTS @ number of élements |
|||
mov r3,#city_name @ sort by name |
|||
mov r4,#'A' @ Alphanumeric |
|||
bl shellSort |
|||
ldr r0,iAdrTableCities @ address number table |
|||
bl displayTable |
|||
100: @ standard end of the program |
|||
mov r0, #0 @ return code |
|||
mov r7, #EXIT @ request to exit program |
|||
svc #0 @ perform the system call |
|||
iAdrszCarriageReturn: .int szCarriageReturn |
|||
iAdrsMessResult: .int sMessResult |
|||
iAdrTableCities: .int TableCities |
|||
iAdrszMessSortHab: .int szMessSortHab |
|||
iAdrszMessSortName: .int szMessSortName |
|||
/***************************************************/ |
|||
/* shell Sort */ |
|||
/***************************************************/ |
|||
/* r0 contains the address of table */ |
|||
/* r1 contains the first element but not use !! */ |
|||
/* this routine use first element at index zero !!! */ |
|||
/* r2 contains the number of element */ |
|||
/* r3 contains the offset of sort zone */ |
|||
/* r4 contains type of sort zone N = numeric A = alphanumeric */ |
|||
shellSort: |
|||
push {r0-r12,lr} @ save registers |
|||
sub sp,#city_end @ reserve area on stack |
|||
mov fp,sp @ frame pointer = stack |
|||
mov r8,r3 @ save offser area sort |
|||
mov r9,r4 @ save type sort |
|||
mov r7,#city_end @ element size |
|||
//vidregtit debut |
|||
sub r12,r2,#1 @ index last item |
|||
mov r6,r12 @ init gap = last item |
|||
1: @ start loop 1 |
|||
lsrs r6,#1 @ gap = gap / 2 |
|||
beq 100f @ if gap = 0 -> end |
|||
mov r3,r6 @ init loop indice 1 |
|||
2: @ start loop 2 |
|||
mul r1,r3,r7 @ offset élement |
|||
mov r2,fp @ save on stack |
|||
bl saveElement |
|||
add r1,r8 @ + offset sort zone |
|||
ldr r4,[r0,r1] @ load first value |
|||
mov r5,r3 @ init loop indice 2 |
|||
3: @ start loop 3 |
|||
cmp r5,r6 @ indice < gap |
|||
blt 8f @ yes -> end loop 2 |
|||
sub r10,r5,r6 @ index = indice - gap |
|||
mul r1,r10,r7 @ offset élement |
|||
add r10,r1,r8 @ + offset sort zone |
|||
ldr r2,[r0,r10] @ load second value |
|||
push {r3,r5} @ save registrars because not enought register |
|||
cmp r9,#'A' @ sort area alapha ? |
|||
beq 4f @ yes |
|||
cmp r4,r2 @ else compare numeric values |
|||
bge 7f @ highter |
|||
b 6f @ lower |
|||
4: @ compare area alphanumeric |
|||
mov r10,#0 @ counter |
|||
5: |
|||
ldrb r3,[r4,r10] @ byte string 1 |
|||
ldrb r5,[r2,r10] @ byte string 2 |
|||
cmp r3,r5 |
|||
bgt 7f |
|||
blt 6f |
|||
cmp r3,#0 @ end string 1 |
|||
beq 7f @ ens comparaison |
|||
add r10,r10,#1 @ else add 1 in counter |
|||
b 5b @ and loop |
|||
6: |
|||
pop {r3,r5} @ restaur registers |
|||
mul r2,r5,r7 @ offset élement |
|||
bl copyElement @ copy element r1 to element r2 |
|||
sub r5,r6 @ indice = indice - gap |
|||
b 3b @ and loop |
|||
7: |
|||
pop {r3,r5} |
|||
8: @ end loop 3 |
|||
mul r1,r5,r7 @ offset destination élement |
|||
mov r2,fp @ restaur element in table |
|||
bl restaurElement |
|||
add r3,#1 @ increment indice 1 |
|||
cmp r3,r12 @ end ? |
|||
ble 2b @ no -> loop 2 |
|||
b 1b @ yes loop for new gap |
|||
100: @ end function |
|||
add sp,#city_end |
|||
pop {r0-r12,lr} @ restaur registers |
|||
bx lr @ return |
|||
/******************************************************************/ |
|||
/* copy table element */ |
|||
/******************************************************************/ |
|||
/* r0 contains the address of table */ |
|||
/* r1 offset origin element */ |
|||
/* r2 offset destination element */ |
|||
copyElement: |
|||
push {r0-r4,lr} @ save registers |
|||
//vidregtit copy |
|||
mov r3,#0 |
|||
add r1,r0 |
|||
add r2,r0 |
|||
1: |
|||
ldrb r4,[r1,r3] |
|||
strb r4,[r2,r3] |
|||
add r3,#1 |
|||
cmp r3,#city_end |
|||
blt 1b |
|||
100: |
|||
pop {r0-r4,lr} |
|||
bx lr |
|||
/******************************************************************/ |
|||
/* save element */ |
|||
/******************************************************************/ |
|||
/* r0 contains the address of table */ |
|||
/* r1 offset origin element */ |
|||
/* r2 address destination */ |
|||
saveElement: |
|||
push {r0-r4,lr} @ save registers |
|||
mov r3,#0 |
|||
add r1,r0 |
|||
1: |
|||
ldrb r4,[r1,r3] |
|||
strb r4,[r2,r3] |
|||
add r3,#1 |
|||
cmp r3,#city_end |
|||
blt 1b |
|||
100: |
|||
pop {r0-r4,lr} |
|||
bx lr |
|||
/******************************************************************/ |
|||
/* restaur element */ |
|||
/******************************************************************/ |
|||
/* r0 contains the address of table */ |
|||
/* r1 offset destination element */ |
|||
/* r2 address origine */ |
|||
restaurElement: |
|||
push {r0-r4,lr} @ save registers |
|||
mov r3,#0 |
|||
add r1,r0 |
|||
1: |
|||
ldrb r4,[r2,r3] |
|||
strb r4,[r1,r3] |
|||
add r3,#1 |
|||
cmp r3,#city_end |
|||
blt 1b |
|||
100: |
|||
pop {r0-r4,lr} |
|||
bx lr |
|||
/******************************************************************/ |
|||
/* Display table elements */ |
|||
/******************************************************************/ |
|||
/* r0 contains the address of table */ |
|||
displayTable: |
|||
push {r0-r6,lr} @ save registers |
|||
mov r2,r0 @ table address |
|||
mov r3,#0 |
|||
mov r6,#city_end |
|||
1: @ loop display table |
|||
mul r4,r3,r6 |
|||
add r4,#city_name |
|||
ldr r1,[r2,r4] |
|||
ldr r0,iAdrsMessResult |
|||
bl strInsertAtCharInc @ put name in message |
|||
mov r5,r0 @ save address of new message |
|||
mul r4,r3,r6 |
|||
add r4,#city_habitants @ and load value |
|||
ldr r0,[r2,r4] |
|||
ldr r1,iAdrsZoneConv |
|||
bl conversion10 @ call decimal conversion |
|||
mov r0,r5 |
|||
ldr r1,iAdrsZoneConv @ insert conversion in message |
|||
bl strInsertAtCharInc |
|||
bl affichageMess @ display message |
|||
add r3,#1 |
|||
cmp r3,#NBELEMENTS - 1 |
|||
ble 1b |
|||
ldr r0,iAdrszCarriageReturn |
|||
bl affichageMess |
|||
100: |
|||
pop {r0-r6,lr} |
|||
bx lr |
|||
iAdrsZoneConv: .int sZoneConv |
|||
/***************************************************/ |
|||
/* ROUTINES INCLUDE */ |
|||
/***************************************************/ |
|||
.include "../affichage.inc" |
|||
</syntaxhighlight> |
|||
<pre> |
|||
Sort table for number of habitants : |
|||
Name : L'Albère number habitants : 83 |
|||
Name : Taillet number habitants : 115 |
|||
Name : Vivés number habitants : 174 |
|||
Name : Les Cluses number habitants : 251 |
|||
Name : Le Perthus number habitants : 586 |
|||
Name : Reynes number habitants : 1354 |
|||
Name : Saint Jean Pla de Corts number habitants : 2153 |
|||
Name : Maureillas number habitants : 2596 |
|||
Name : Le Boulou number habitants : 5554 |
|||
Name : Ceret number habitants : 7705 |
|||
Sort table for name of city : |
|||
Name : Ceret number habitants : 7705 |
|||
Name : L'Albère number habitants : 83 |
|||
Name : Le Boulou number habitants : 5554 |
|||
Name : Le Perthus number habitants : 586 |
|||
Name : Les Cluses number habitants : 251 |
|||
Name : Maureillas number habitants : 2596 |
|||
Name : Reynes number habitants : 1354 |
|||
Name : Saint Jean Pla de Corts number habitants : 2153 |
|||
Name : Taillet number habitants : 115 |
|||
Name : Vivés number habitants : 174 |
|||
</pre> |
|||
=={{header|Arturo}}== |
|||
<syntaxhighlight lang="arturo">people: [ |
|||
["joe" 120] |
|||
["foo" 31] |
|||
["bar" 51] |
|||
] |
|||
print arrange people 'x -> x\0</syntaxhighlight> |
|||
{{out}} |
|||
<pre>[bar 51] [foo 31] [joe 120]</pre> |
|||
=={{header|ATS}}== |
|||
<syntaxhighlight lang="ats">#include "share/atspre_staload.hats" |
|||
typedef pair = |
|||
'{ |
|||
name = string, |
|||
value = string |
|||
} |
|||
fn |
|||
sort_pairs {n : int} |
|||
(pairs : &array (pair, n) >> _, |
|||
n : size_t n) |
|||
:<!wrt> void = |
|||
let |
|||
implement |
|||
array_quicksort$cmp<pair> (x, y) = |
|||
strcmp (x.name, y.name) |
|||
in |
|||
array_quicksort<pair> (pairs, n) |
|||
end |
|||
implement |
|||
main0 () = |
|||
let |
|||
val pairs_list : list (pair, 9) = |
|||
$list |
|||
('{name = "Warsaw", value = "Poland"}, |
|||
'{name = "Prague", value = "Czech Republic"}, |
|||
'{name = "London", value = "United Kingdom"}, |
|||
'{name = "Paris", value = "France"}, |
|||
'{name = "Madrid", value = "Spain"}, |
|||
'{name = "Berlin", value = "Germany"}, |
|||
'{name = "Rome", value = "Italy"}, |
|||
'{name = "Moscow", value = "Russia"}, |
|||
'{name = "Budapest", value = "Hungary"}) |
|||
var pairs_array : @[pair][9] |
|||
val () = array_initize_list<pair> (pairs_array, 9, pairs_list) |
|||
val () = sort_pairs (pairs_array, i2sz 9) |
|||
var i : [i : nat | i <= 9] int i |
|||
in |
|||
for (i := 0; i <> 9; i := succ i) |
|||
println! (pairs_array[i].name, " -> ", pairs_array[i].value) |
|||
end</syntaxhighlight> |
|||
{{out}} |
|||
<pre>$ patscc -DATS_MEMALLOC_GCBDW -O3 sort_composite_structures.dats -lgc && ./a.out |
|||
Berlin -> Germany |
|||
Budapest -> Hungary |
|||
London -> United Kingdom |
|||
Madrid -> Spain |
|||
Moscow -> Russia |
|||
Paris -> France |
|||
Prague -> Czech Republic |
|||
Rome -> Italy |
|||
Warsaw -> Poland</pre> |
|||
=={{header|AutoHotkey}}== |
=={{header|AutoHotkey}}== |
||
built ListView Gui, contains a table sorting function which can be used for this. |
built ListView Gui, contains a table sorting function which can be used for this. |
||
< |
<syntaxhighlight lang="autohotkey">start: |
||
Gui, Add, ListView, r20 w200, 1|2 |
Gui, Add, ListView, r20 w200, 1|2 |
||
data = |
data = |
||
Line 225: | Line 1,178: | ||
GuiClose: |
GuiClose: |
||
ExitApp</ |
ExitApp</syntaxhighlight> |
||
=={{header| |
=={{header|AWK}}== |
||
<syntaxhighlight lang="awk"> |
|||
{{works with|g++|4.1.2}} |
|||
# syntax: GAWK -f SORT_AN_ARRAY_OF_COMPOSITE_STRUCTURES.AWK |
|||
<lang cpp> |
|||
BEGIN { |
|||
#include <iterator> |
|||
# AWK lacks structures but one can be simulated using an associative array. |
|||
#include <algorithm> |
|||
arr["eight 8 "] |
|||
#include <iostream> |
|||
arr["two 2 "] |
|||
arr["five 5 "] |
|||
arr["nine 9 "] |
|||
arr["one 1 "] |
|||
arr["three 3 "] |
|||
arr["six 6 "] |
|||
arr["seven 7 "] |
|||
arr["four 4 "] |
|||
arr["ten 10"] |
|||
arr["zero 0 "] |
|||
arr["twelve 12"] |
|||
arr["minus2 -2"] |
|||
show(1,7,"@val_str_asc","name") # use name part of name-value pair |
|||
show(8,9,"@val_num_asc","value") # use value part of name-value pair |
|||
exit(0) |
|||
} |
|||
function show(a,b,sequence,description, i,x) { |
|||
PROCINFO["sorted_in"] = "@unsorted" |
|||
for (i in arr) { |
|||
x = substr(i,a,b) |
|||
sub(/ +/,"",x) |
|||
arr[i] = x |
|||
} |
|||
PROCINFO["sorted_in"] = sequence |
|||
printf("sorted by %s:",description) |
|||
for (i in arr) { |
|||
printf(" %s",arr[i]) |
|||
} |
|||
printf("\n") |
|||
} |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
sorted by name: eight five four minus2 nine one seven six ten three twelve two zero |
|||
sorted by value: -2 0 1 2 3 4 5 6 7 8 9 10 12 |
|||
</pre> |
|||
=={{header|Babel}}== |
|||
template<typename Struct, typename MemberType> class less_member |
|||
First, we construct a list-of-maps and assign it to variable baz. Next, we sort baz by key "foo" and assign it to variable bop. Finally, we lookup "foo" in each map in list bop and display the resulting list of numbers - they are in sorted order. |
|||
<syntaxhighlight lang="babel">babel> baz ([map "foo" 3 "bar" 17] [map "foo" 4 "bar" 18] [map "foo" 5 "bar" 19] [map "foo" 0 "bar" 20]) < |
|||
babel> bop baz { <- "foo" lumap ! -> "foo" lumap ! lt? } lssort ! < |
|||
babel> bop {"foo" lumap !} over ! lsnum ! |
|||
( 0 3 4 5 )</syntaxhighlight> |
|||
The same technique works for any list of data-objects you may have. User-code can expect to have the top two elements of the stack set to be the two objects to be compared. Simply access the relevant field in each object, and then perform a comparison. For example, here is a list of pairs sorted by first element: |
|||
<syntaxhighlight lang="babel">babel> 20 lsrange ! {1 randlf 2 rem} lssort ! 2 group ! --> this creates a shuffled list of pairs |
|||
babel> dup {lsnum !} ... --> display the shuffled list, pair-by-pair |
|||
( 11 10 ) |
|||
( 15 13 ) |
|||
( 12 16 ) |
|||
( 17 3 ) |
|||
( 14 5 ) |
|||
( 4 19 ) |
|||
( 18 9 ) |
|||
( 1 7 ) |
|||
( 8 6 ) |
|||
( 0 2 ) |
|||
babel> {<- car -> car lt? } lssort ! --> sort the list by first element of each pair |
|||
babel> dup {lsnum !} ... --> display the sorted list, pair-by-pair |
|||
( 0 2 ) |
|||
( 1 7 ) |
|||
( 4 19 ) |
|||
( 8 6 ) |
|||
( 11 10 ) |
|||
( 12 16 ) |
|||
( 14 5 ) |
|||
( 15 13 ) |
|||
( 17 3 ) |
|||
( 18 9 )</syntaxhighlight> |
|||
The gpsort utility performs this kind of comparison "automagically" by leveraging the ordering of Babel's underlying data-structure. Using the shuffled list from the example above: |
|||
<syntaxhighlight lang="babel">babel> gpsort ! |
|||
babel> dup {lsnum !} ... |
|||
( 0 2 ) |
|||
( 1 7 ) |
|||
( 4 19 ) |
|||
( 8 6 ) |
|||
( 11 10 ) |
|||
( 12 16 ) |
|||
( 14 5 ) |
|||
( 15 13 ) |
|||
( 17 3 ) |
|||
( 18 9 )</syntaxhighlight> |
|||
Note that gpsort will not work for the case where you want to sort on the second element of a list of pairs. But it will work for performing a canonical sort on numbers, arrays of numbers, lists of numbers, lists of lists, lists of arrays, arrays of lists, and so on. You should not use gpsort with strings; use lexsort or strsort instead. Here's an example of sorting a mixture of pairs and triples using gpsort: |
|||
<syntaxhighlight lang="babel">babel> dup {lsnum !} ... --> display the shuffled list of pairs and triples |
|||
( 7 2 ) |
|||
( 6 4 ) |
|||
( 8 9 ) |
|||
( 0 5 ) |
|||
( 5 14 0 ) |
|||
( 3 1 ) |
|||
( 9 6 10 ) |
|||
( 1 12 4 ) |
|||
( 11 13 7 ) |
|||
( 8 2 3 ) |
|||
babel> gpsort ! --> sort the list |
|||
babel> dup {lsnum !} ... --> display the result |
|||
( 0 5 ) |
|||
( 3 1 ) |
|||
( 6 4 ) |
|||
( 7 2 ) |
|||
( 8 9 ) |
|||
( 1 12 4 ) |
|||
( 5 14 0 ) |
|||
( 8 2 3 ) |
|||
( 9 6 10 ) |
|||
( 11 13 7 )</syntaxhighlight> |
|||
=={{header|BBC BASIC}}== |
|||
{{works with|BBC BASIC for Windows}} |
|||
Uses the supplied SORTSALIB library. |
|||
<syntaxhighlight lang="bbcbasic"> INSTALL @lib$+"SORTSALIB" |
|||
sort% = FN_sortSAinit(0,0) |
|||
DIM pair{name$, number%} |
|||
DIM array{(10)} = pair{} |
|||
FOR i% = 1 TO DIM(array{()}, 1) |
|||
READ array{(i%)}.name$, array{(i%)}.number% |
|||
NEXT |
|||
DATA "Eight", 8, "Two", 2, "Five", 5, "Nine", 9, "One", 1 |
|||
DATA "Three", 3, "Six", 6, "Seven", 7, "Four", 4, "Ten", 10 |
|||
C% = DIM(array{()}, 1) |
|||
D% = 1 |
|||
CALL sort%, array{()}, array{(0)}.number%, array{(0)}.name$ |
|||
FOR i% = 1 TO DIM(array{()}, 1) |
|||
PRINT array{(i%)}.name$, array{(i%)}.number% |
|||
NEXT</syntaxhighlight> |
|||
Output: |
|||
<pre> |
|||
One 1 |
|||
Two 2 |
|||
Three 3 |
|||
Four 4 |
|||
Five 5 |
|||
Six 6 |
|||
Seven 7 |
|||
Eight 8 |
|||
Nine 9 |
|||
Ten 10 |
|||
</pre> |
|||
=={{header|Bracmat}}== |
|||
The easiest way to sort an array of elements in Bracmat is to handle it as a sum of terms. A sum, when evaluated, is automatically sorted. |
|||
<syntaxhighlight lang="bracmat">( (tab=("C++",1979)+(Ada,1983)+(Ruby,1995)+(Eiffel,1985)) |
|||
& out$"unsorted array:" |
|||
& lst$tab |
|||
& out$("sorted array:" !tab \n) |
|||
& out$"But tab is still unsorted:" |
|||
& lst$tab |
|||
);</syntaxhighlight> |
|||
Output: |
|||
<pre>unsorted array: |
|||
(tab= |
|||
("C++",1979)+(Ada,1983)+(Ruby,1995)+(Eiffel,1985) |
|||
); |
|||
sorted array: |
|||
(Ada,1983)+(C++,1979)+(Eiffel,1985)+(Ruby,1995) |
|||
But tab is still unsorted: |
|||
(tab= |
|||
("C++",1979)+(Ada,1983)+(Ruby,1995)+(Eiffel,1985) |
|||
);</pre> |
|||
When evaluating <code>!tab</code>, the expression bound to the variable name <code>tab</code> is sorted, but the unevaluated expression is still bound to <code>tab</code>. An assignment binds the sorted expression to <code>tab</code>: |
|||
<syntaxhighlight lang="bracmat">( !tab:?tab |
|||
& out$"Now tab is sorted:" |
|||
& lst$tab |
|||
);</syntaxhighlight> |
|||
Output: |
|||
<pre>Now tab is sorted: |
|||
(tab= |
|||
(Ada,1983)+("C++",1979)+(Eiffel,1985)+(Ruby,1995) |
|||
);</pre> |
|||
To sort an array that is not a sum expression, we can convert it to a sum: |
|||
<syntaxhighlight lang="bracmat">( ((name.map),(weight.9),(value.150)) |
|||
((name.compass),(weight.13),(value.35)) |
|||
((name.water),(weight.153),(value.200)) |
|||
((name.sandwich),(weight.50),(value.60)) |
|||
((name.glucose),(weight.15),(value.60)) |
|||
: ?array |
|||
& ( reverse |
|||
= e A |
|||
. :?A |
|||
& whl'(!arg:%?e ?arg&!e !A:?A) |
|||
& !A |
|||
) |
|||
& out$("Array before sorting:" !array \n) |
|||
& 0:?sum |
|||
& whl |
|||
' (!array:%?element ?array&!element+!sum:?sum) |
|||
& whl |
|||
' (!sum:%?element+?sum&!element !array:?array) |
|||
& out$("Array after sorting (descending order):" !array \n) |
|||
& out$("Array after sorting (ascending order):" reverse$!array \n) |
|||
);</syntaxhighlight> |
|||
Output: |
|||
<pre> Array before sorting: |
|||
((name.map),(weight.9),(value.150)) |
|||
((name.compass),(weight.13),(value.35)) |
|||
((name.water),(weight.153),(value.200)) |
|||
((name.sandwich),(weight.50),(value.60)) |
|||
((name.glucose),(weight.15),(value.60)) |
|||
Array after sorting (descending order): |
|||
((name.water),(weight.153),(value.200)) |
|||
((name.sandwich),(weight.50),(value.60)) |
|||
((name.map),(weight.9),(value.150)) |
|||
((name.glucose),(weight.15),(value.60)) |
|||
((name.compass),(weight.13),(value.35)) |
|||
Array after sorting (ascending order): |
|||
((name.compass),(weight.13),(value.35)) |
|||
((name.glucose),(weight.15),(value.60)) |
|||
((name.map),(weight.9),(value.150)) |
|||
((name.sandwich),(weight.50),(value.60)) |
|||
((name.water),(weight.153),(value.200))</pre> |
|||
Bracmat has a left to right sorting order. If an array must be sorted on another field than the first field, that other field has to be made the first field. After sorting, the fields can take their original positions. |
|||
<syntaxhighlight lang="bracmat">( (Joe,5531) |
|||
(Adam,2341) |
|||
(Bernie,122) |
|||
(Walter,1234) |
|||
(David,19) |
|||
: ?array |
|||
& 0:?sum |
|||
& whl |
|||
' ( !array:(?car,?cdr) ?array |
|||
& (!cdr.!car)+!sum:?sum |
|||
) |
|||
& whl |
|||
' ( !sum:(?car.?cdr)+?sum |
|||
& (!cdr,!car) !array:?array |
|||
) |
|||
& out$("Array after sorting on second field (descending order):" !array \n) |
|||
& out |
|||
$ ( "Array after sorting on second field (ascending order):" |
|||
reverse$!array |
|||
\n |
|||
) |
|||
);</syntaxhighlight> |
|||
Output: |
|||
<pre> Array after sorting on second field (descending order): |
|||
(Joe,5531) |
|||
(Adam,2341) |
|||
(Walter,1234) |
|||
(Bernie,122) |
|||
(David,19) |
|||
Array after sorting on second field (ascending order): |
|||
(David,19) |
|||
(Bernie,122) |
|||
(Walter,1234) |
|||
(Adam,2341) |
|||
(Joe,5531)</pre> |
|||
=={{header|C}}== |
|||
Using qsort, from the standard library. |
|||
<syntaxhighlight lang="c"> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <ctype.h> |
|||
typedef struct twoStringsStruct { |
|||
char * key, *value; |
|||
} sTwoStrings; |
|||
int ord( char v ) |
|||
{ |
{ |
||
static char *dgts = "012345679"; |
|||
public: |
|||
char *cp; |
|||
less_member(MemberType Struct::*m): |
|||
for (cp=dgts; v != *cp; cp++); |
|||
member(m) |
|||
return (cp-dgts); |
|||
{ |
|||
} |
|||
bool operator()(Struct const& s1, Struct const& s2) |
|||
{ |
|||
return s1.*member < s2.*member; |
|||
} |
|||
private: |
|||
MemberType Struct::*member; |
|||
}; |
|||
int cmprStrgs(const sTwoStrings *s1,const sTwoStrings *s2) |
|||
template<typename Struct, typename MemberType> |
|||
less_member<Struct, MemberType> make_less_member(MemberType Struct::* m) |
|||
{ |
{ |
||
char *p1 = s1->key; |
|||
return m; |
|||
char *p2 = s2->key; |
|||
char *mrk1, *mrk2; |
|||
while ((tolower(*p1) == tolower(*p2)) && *p1) { p1++; p2++;} |
|||
if (isdigit(*p1) && isdigit(*p2)) { |
|||
long v1, v2; |
|||
if ((*p1 == '0') ||(*p2 == '0')) { |
|||
while (p1 > s1->key) { |
|||
p1--; p2--; |
|||
if (*p1 != '0') break; |
|||
} |
|||
if (!isdigit(*p1)) { |
|||
p1++; p2++; |
|||
} |
|||
} |
|||
mrk1 = p1; mrk2 = p2; |
|||
v1 = 0; |
|||
while(isdigit(*p1)) { |
|||
v1 = 10*v1+ord(*p1); |
|||
p1++; |
|||
} |
|||
v2 = 0; |
|||
while(isdigit(*p2)) { |
|||
v2 = 10*v2+ord(*p2); |
|||
p2++; |
|||
} |
|||
if (v1 == v2) |
|||
return(p2-mrk2)-(p1-mrk1); |
|||
return v1 - v2; |
|||
} |
|||
if (tolower(*p1) != tolower(*p2)) |
|||
return (tolower(*p1) - tolower(*p2)); |
|||
for(p1=s1->key, p2=s2->key; (*p1 == *p2) && *p1; p1++, p2++); |
|||
return (*p1 -*p2); |
|||
} |
} |
||
int maxstrlen( char *a, char *b) |
|||
template<typename FwdIter, typename MemberPtrType> |
|||
void sort_for_member(FwdIter first, FwdIter last, MemberPtrType m) |
|||
{ |
{ |
||
int la = strlen(a); |
|||
std::sort(first, last, make_less_member(m)); |
|||
int lb = strlen(b); |
|||
return (la>lb)? la : lb; |
|||
} |
} |
||
int main() |
|||
struct entry |
|||
{ |
{ |
||
sTwoStrings toBsorted[] = { |
|||
{ "Beta11a", "many" }, |
|||
{ "alpha1", "This" }, |
|||
{ "Betamax", "sorted." }, |
|||
{ "beta3", "order" }, |
|||
{ "beta11a", "strings" }, |
|||
{ "beta001", "is" }, |
|||
{ "beta11", "which" }, |
|||
{ "beta041", "be" }, |
|||
{ "beta05", "in" }, |
|||
{ "beta1", "the" }, |
|||
{ "beta40", "should" }, |
|||
}; |
|||
#define ASIZE (sizeof(toBsorted)/sizeof(sTwoStrings)) |
|||
int k, maxlens[ASIZE]; |
|||
char format[12]; |
|||
sTwoStrings *cp; |
|||
qsort( (void*)toBsorted, ASIZE, sizeof(sTwoStrings),cmprStrgs); |
|||
for (k=0,cp=toBsorted; k < ASIZE; k++,cp++) { |
|||
maxlens[k] = maxstrlen(cp->key, cp->value); |
|||
sprintf(format," %%-%ds", maxlens[k]); |
|||
printf(format, toBsorted[k].value); |
|||
} |
|||
printf("\n"); |
|||
for (k=0; k < ASIZE; k++) { |
|||
sprintf(format," %%-%ds", maxlens[k]); |
|||
printf(format, toBsorted[k].key); |
|||
} |
|||
printf("\n"); |
|||
return 0; |
|||
}</syntaxhighlight> |
|||
Output: |
|||
<pre> This is the order in which many strings should be sorted. |
|||
alpha1 beta001 beta1 beta3 beta05 beta11 Beta11a beta11a beta40 beta041 Betamax</pre> |
|||
=={{header|C sharp|C#}}== |
|||
{{works with|C sharp|C#|3+}} |
|||
<syntaxhighlight lang="csharp">using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
class Program |
|||
{ |
|||
struct Entry |
|||
{ |
|||
public Entry(string name, double value) { Name = name; Value = value; } |
|||
public string Name; |
|||
public double Value; |
|||
} |
|||
static void Main(string[] args) |
|||
{ |
|||
var Elements = new List<Entry> |
|||
{ |
|||
new Entry("Krypton", 83.798), new Entry("Beryllium", 9.012182), new Entry("Silicon", 28.0855), |
|||
new Entry("Cobalt", 58.933195), new Entry("Selenium", 78.96), new Entry("Germanium", 72.64) |
|||
}; |
|||
var sortedElements = Elements.OrderBy(e => e.Name); |
|||
foreach (Entry e in sortedElements) |
|||
Console.WriteLine("{0,-11}{1}", e.Name, e.Value); |
|||
} |
|||
}</syntaxhighlight> |
|||
Output: |
|||
<pre>Beryllium 9.012182 |
|||
Cobalt 58.933195 |
|||
Germanium 72.64 |
|||
Krypton 83.798 |
|||
Selenium 78.96 |
|||
Silicon 28.0855</pre> |
|||
=={{header|C++}}== |
|||
Uses C++11. Compile with |
|||
g++ -std=c++11 sort.cpp |
|||
<syntaxhighlight lang="cpp">#include <algorithm> |
|||
#include <iostream> |
|||
#include <string> |
|||
struct entry { |
|||
std::string name; |
std::string name; |
||
std::string value; |
std::string value; |
||
}; |
}; |
||
int main() |
int main() { |
||
entry array[] = { { "grass", "green" }, { "snow", "white" }, |
|||
{ |
|||
{ "sky", "blue" }, { "cherry", "red" } }; |
|||
{ "snow", "white" }, |
|||
{ "sky", "blue" }, |
|||
{ "cherry", "red" } }; |
|||
std::cout << "before sorting:\n\n"; |
|||
for (int i = 0; i < 4; ++i) |
|||
std::cout << "index: " << i << ", name: " << array[i].name |
|||
<< ", value: " << array[i].value << "\n"; |
|||
std::cout << "Before sorting:\n"; |
|||
sort_for_member(array, array+4, &entry::name); |
|||
for (const auto &e : array) { |
|||
std::cout << "{" << e.name << ", " << e.value << "}\n"; |
|||
} |
|||
std::sort(std::begin(array), std::end(array), |
|||
std::cout << "\nafter sorting:\n\n"; |
|||
[](const entry & a, const entry & b) { |
|||
return a.name < b.name; |
|||
}); |
|||
<< ", value: " << array[i].value << "\n"; |
|||
return 0; |
|||
std::cout << "After sorting:\n"; |
|||
} |
|||
for (const auto &e : array) { |
|||
</lang> |
|||
std::cout << "{" << e.name << ", " << e.value << "}\n"; |
|||
} |
|||
}</syntaxhighlight> |
|||
Output: |
|||
<pre> |
|||
Before sorting: |
|||
{grass, green} |
|||
{snow, white} |
|||
{sky, blue} |
|||
{cherry, red} |
|||
After sorting: |
|||
{cherry, red} |
|||
{grass, green} |
|||
{sky, blue} |
|||
{snow, white} |
|||
</pre> |
|||
=={{header|Clojure}}== |
|||
Clojure has a ''sort-by'' function which takes a ''keyfn'' and a ''coll''. It returns a sorted sequence of the items in ''coll'', where the sort order is determined by comparing ''(keyfn item)''. |
|||
<syntaxhighlight lang="clojure"> |
|||
;; Gathered with Google Squared |
|||
(def *langs* [["Clojure" 2007] ["Common Lisp" 1984] ["Java" 1995] ["Haskell" 1990] |
|||
["Lisp" 1958] ["Scheme" 1975]]) |
|||
user> (sort-by second *langs*) ; using a keyfn |
|||
(["Lisp" 1958] ["Scheme" 1975] ["Common Lisp" 1984] ["Haskell" 1990] ["Java" 1995] ["Clojure" 2007]) |
|||
</syntaxhighlight> |
|||
You can also supply a comparator (using ''compare'' or a sibling of ''<''). A comparator can be used with the regular ''sort'' function or the ''sort-by'' function. In the latter case, the comparator will be used on ''(keyfn item)'' instead of ''item''. |
|||
<syntaxhighlight lang="clojure"> |
|||
user> (sort #(compare (second %1) (second %2)) *langs*) ; using a comparator |
|||
(["Lisp" 1958] ["Scheme" 1975] ["Common Lisp" 1984] ["Haskell" 1990] ["Java" 1995] ["Clojure" 2007]) |
|||
user> (sort-by second > *langs*) ; using a keyfn and a comparator |
|||
(["Clojure" 2007] ["Java" 1995] ["Haskell" 1990] ["Common Lisp" 1984] ["Scheme" 1975] ["Lisp" 1958]) |
|||
</syntaxhighlight> |
|||
Read the docstring of ''sort'' and ''sort-by'' for more info. |
|||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
||
Line 293: | Line 1,680: | ||
Let's define a composite structure of U.S. states and average test scores. |
Let's define a composite structure of U.S. states and average test scores. |
||
<syntaxhighlight lang="lisp">CL-USER> (defparameter *test-scores* '(("texas" 68.9) ("ohio" 87.8) ("california" 76.2) ("new york" 88.2)) ) |
|||
*TEST-SCORES*</syntaxhighlight> |
|||
We can sort by the state name by supplying a one-argument key function that is called by the ''sort'' function to determine the value to compare. In this case, the function is ''first'' will retrieve the state name: |
We can sort by the state name by supplying a one-argument key function that is called by the ''sort'' function to determine the value to compare. In this case, the function is ''first'' will retrieve the state name: |
||
<syntaxhighlight lang="lisp">CL-USER> (sort (copy-list *test-scores*) #'string-lessp :key #'first) |
|||
(("california" 76.2) ("new york" 88.2) ("ohio" 87.8) ("texas" 68.9))</syntaxhighlight> |
|||
we can also sort by the test scores by supplying a different key function that return the test score instead: |
we can also sort by the test scores by supplying a different key function that return the test score instead: |
||
<syntaxhighlight lang="lisp">CL-USER> (sort (copy-list *test-scores*) #'< :key #'second) |
|||
(("texas" 68.9) ("california" 76.2) ("ohio" 87.8) ("new york" 88.2))</syntaxhighlight> |
|||
=={{header|D}}== |
=={{header|D}}== |
||
<syntaxhighlight lang="d">import std.stdio, std.algorithm; |
|||
{{works with|D|2.011+}} |
|||
<lang d>module sortcomposite ; |
|||
import std.stdio ; |
|||
import std.algorithm ; |
|||
struct |
struct Pair { string name, value; } |
||
string name ; |
|||
string value ; |
|||
int amount ; |
|||
string toString() { |
|||
return "<" ~ name ~ "|" ~ value ~ "|" ~ std.string.toString(amount) ~ ">" ; |
|||
} |
|||
} |
|||
T[] csort(string FIELD , T)(T[] arr) { |
|||
mixin("sort!(\"a." ~ FIELD ~ " < b." ~ FIELD ~ "\")(arr) ;") ; |
|||
//compile as statement : |
|||
// sort!("a.FIELD < b.FIELD")(arr) ; |
|||
return arr ; |
|||
} |
|||
void main() { |
void main() { |
||
Pair[] pairs = [{"Joe", "5531"}, |
|||
{"Adam", "2341"}, |
|||
{"Bernie", "122"}, |
|||
{"Walter", "1234"}, |
|||
{"David", "19"}]; |
|||
pairs.schwartzSort!q{ a.name }.writeln; |
|||
}</syntaxhighlight> |
|||
writefln(datas) ; |
|||
{{out}} |
|||
writefln(csort!("value")(datas)) ; |
|||
<pre>[Pair("Adam", "2341"), Pair("Bernie", "122"), Pair("David", "19"), Pair("Joe", "5531"), Pair("Walter", "1234")]</pre> |
|||
writefln(csort!("amount")(datas)) ; |
|||
}</lang> |
|||
=={{header|Delphi}}== |
|||
'''Limitation''': The field name has to be compile-time determined. |
|||
<syntaxhighlight lang="delphi">program SortCompositeStructures; |
|||
{$APPTYPE CONSOLE} |
|||
uses SysUtils, Generics.Collections, Generics.Defaults; |
|||
type |
|||
TStructurePair = record |
|||
name: string; |
|||
value: string; |
|||
constructor Create(const aName, aValue: string); |
|||
end; |
|||
constructor TStructurePair.Create(const aName, aValue: string); |
|||
begin |
|||
name := aName; |
|||
value := aValue; |
|||
end; |
|||
var |
|||
lArray: array of TStructurePair; |
|||
begin |
|||
SetLength(lArray, 3); |
|||
lArray[0] := TStructurePair.Create('dog', 'rex'); |
|||
lArray[1] := TStructurePair.Create('cat', 'simba'); |
|||
lArray[2] := TStructurePair.Create('horse', 'trigger'); |
|||
TArray.Sort<TStructurePair>(lArray , TDelegatedComparer<TStructurePair>.Construct( |
|||
function(const Left, Right: TStructurePair): Integer |
|||
begin |
|||
Result := CompareText(Left.Name, Right.Name); |
|||
end)); |
|||
end.</syntaxhighlight> |
|||
=={{header|E}}== |
=={{header|E}}== |
||
<syntaxhighlight lang="e">def compareBy(keyfn) { # This ought to be in the standard library |
|||
[[Category:E examples needing attention]] |
|||
<lang e>def compareBy(keyfn) { # This ought to be in the standard library |
|||
return def comparer(a, b) { |
return def comparer(a, b) { |
||
return keyfn(a).op__cmp(keyfn(b)) |
return keyfn(a).op__cmp(keyfn(b)) |
||
Line 355: | Line 1,760: | ||
] |
] |
||
println(x.sort(compareBy(fn [name,_] { name })))</ |
println(x.sort(compareBy(fn [name,_] { name })))</syntaxhighlight> |
||
=={{header| |
=={{header|EchoLisp}}== |
||
<syntaxhighlight lang="scheme"> |
|||
{{works with|Fortran|90 and later}} |
|||
;; sorting (name value) by name - Ignoring case |
|||
Standard Fortran has no built-in sort function although some compilers add them. The following example uses an insertion sort. |
|||
(define (name a) (first a)) |
|||
<lang fortran> PROGRAM EXAMPLE |
|||
(define( sort-proc a b) |
|||
IMPLICIT NONE |
|||
(string-ci<? (name a) (name b))) |
|||
(define people |
|||
'(("😎" -42) ("albert" 33) ("Simone" 44) ("Antoinette" 42) ("elvis" 666) ("😃" 1000))) |
|||
(list-sort sort-proc people) |
|||
→ (("albert" 33) ("Antoinette" 42) ("elvis" 666) ("Simone" 44) ("😃" 1000) ("😎" -42)) |
|||
</syntaxhighlight> |
|||
=={{header|Elena}}== |
|||
ELENA 6.x : |
|||
<syntaxhighlight lang="elena">import system'routines; |
|||
import extensions; |
|||
public program() |
|||
TYPE Pair |
|||
{ |
|||
CHARACTER(6) :: name |
|||
var elements := new object[]{ |
|||
KeyValue.new("Krypton", 83.798r), |
|||
END TYPE Pair |
|||
KeyValue.new("Beryllium", 9.012182r), |
|||
KeyValue.new("Silicon", 28.0855r), |
|||
KeyValue.new("Cobalt", 58.933195r), |
|||
KeyValue.new("Selenium", 78.96r), |
|||
KeyValue.new("Germanium", 72.64r)}; |
|||
var sorted := elements.sort::(former,later => former.Key < later.Key ); |
|||
TYPE(Pair) :: rcc(10), temp |
|||
INTEGER :: i, j |
|||
sorted.forEach::(element) |
|||
rcc(1) = Pair("Black", "0") |
|||
{ |
|||
rcc(2) = Pair("Brown", "1") |
|||
console.printLine(element.Key," - ",element) |
|||
rcc(3) = Pair("Red", "2") |
|||
} |
|||
rcc(4) = Pair("Orange", "3") |
|||
}</syntaxhighlight> |
|||
rcc(5) = Pair("Yellow", "4") |
|||
rcc(6) = Pair("Green", "5") |
|||
=={{header|Elixir}}== |
|||
rcc(7) = Pair("Blue", "6") |
|||
<syntaxhighlight lang="elixir">defmodule Person do |
|||
rcc(8) = Pair("Violet", "7") |
|||
defstruct name: "", value: 0 |
|||
rcc(9) = Pair("Grey", "8") |
|||
end |
|||
rcc(10) = Pair("White", "9") |
|||
list = [struct(Person, [name: "Joe", value: 3]), |
|||
DO i = 2, SIZE(rcc) |
|||
struct(Person, [name: "Bill", value: 4]), |
|||
j = i - 1 |
|||
struct(Person, [name: "Alice", value: 20]), |
|||
temp = rcc(i) |
|||
struct(Person, [name: "Harry", value: 3])] |
|||
rcc(j+1) = rcc(j) |
|||
Enum.sort(list) |> Enum.each(fn x -> IO.inspect x end) |
|||
j = j - 1 |
|||
IO.puts "" |
|||
END DO |
|||
Enum.sort_by(list, &(&1.value)) |> Enum.each(&IO.inspect &1)</syntaxhighlight> |
|||
rcc(j+1) = temp |
|||
END DO |
|||
{{out}} |
|||
<pre> |
|||
%Person{name: "Alice", value: 20} |
|||
%Person{name: "Bill", value: 4} |
|||
%Person{name: "Harry", value: 3} |
|||
%Person{name: "Joe", value: 3} |
|||
%Person{name: "Joe", value: 3} |
|||
%Person{name: "Harry", value: 3} |
|||
%Person{name: "Bill", value: 4} |
|||
%Person{name: "Alice", value: 20} |
|||
</pre> |
|||
=={{header|Erlang}}== |
|||
Any Erlang type can be compared to any Erlang type. As such, nothing special needs to be done: |
|||
<syntaxhighlight lang="erlang">1> lists:sort([{{2006,2007},"Ducks"}, |
|||
{{2000,2001},"Avalanche"}, |
|||
{{2002,2003},"Devils"}, |
|||
{{2001,2002},"Red Wings"}, |
|||
{{2003,2004},"Lightning"}, |
|||
{{2004,2005},"N/A: lockout"}, |
|||
{{2005,2006},"Hurricanes"}, |
|||
{{1999,2000},"Devils"}, |
|||
{{2007,2008},"Red Wings"}, |
|||
{{2008,2009},"Penguins"}]). |
|||
[{{1999,2000},"Devils"}, |
|||
{{2000,2001},"Avalanche"}, |
|||
{{2001,2002},"Red Wings"}, |
|||
{{2002,2003},"Devils"}, |
|||
{{2003,2004},"Lightning"}, |
|||
{{2004,2005},"N/A: lockout"}, |
|||
{{2005,2006},"Hurricanes"}, |
|||
{{2006,2007},"Ducks"}, |
|||
{{2007,2008},"Red Wings"}, |
|||
{{2008,2009},"Penguins"}]</syntaxhighlight> |
|||
It is also possible to sort with custom functions, in this case by the team's name: |
|||
<syntaxhighlight lang="erlang">2> F = fun({_,X},{_,Y}) -> X < Y end. |
|||
#Fun<erl_eval.12.113037538> |
|||
3> lists:usort(F, [{{2006,2007},"Ducks"}, |
|||
{{2000,2001},"Avalanche"}, |
|||
{{2002,2003},"Devils"}, |
|||
{{2001,2002},"Red Wings"}, |
|||
{{2003,2004},"Lightning"}, |
|||
{{2004,2005},"N/A: lockout"}, |
|||
{{2005,2006},"Hurricanes"}, |
|||
{{1999,2000},"Devils"}, |
|||
{{2007,2008},"Red Wings"}, |
|||
{{2008,2009},"Penguins"}]). |
|||
[{{2000,2001},"Avalanche"}, |
|||
{{1999,2000},"Devils"}, |
|||
{{2002,2003},"Devils"}, |
|||
{{2006,2007},"Ducks"}, |
|||
{{2005,2006},"Hurricanes"}, |
|||
{{2003,2004},"Lightning"}, |
|||
{{2004,2005},"N/A: lockout"}, |
|||
{{2008,2009},"Penguins"}, |
|||
{{2007,2008},"Red Wings"}, |
|||
{{2001,2002},"Red Wings"}]</syntaxhighlight> |
|||
=={{header|Euphoria}}== |
|||
<syntaxhighlight lang="euphoria">include sort.e |
|||
include misc.e |
|||
constant NAME = 1 |
|||
function compare_names(sequence a, sequence b) |
|||
return compare(a[NAME],b[NAME]) |
|||
end function |
|||
sequence s |
|||
s = { { "grass", "green" }, |
|||
{ "snow", "white" }, |
|||
{ "sky", "blue" }, |
|||
{ "cherry", "red" } } |
|||
pretty_print(1,custom_sort(routine_id("compare_names"),s),{2})</syntaxhighlight> |
|||
Output: |
|||
<pre>{ |
|||
{ |
|||
"cherry", |
|||
"red" |
|||
}, |
|||
{ |
|||
"grass", |
|||
"green" |
|||
}, |
|||
{ |
|||
"sky", |
|||
"blue" |
|||
}, |
|||
{ |
|||
"snow", |
|||
"white" |
|||
} |
|||
}</pre> |
|||
=={{header|F_Sharp|F#}}== |
|||
F# has <code>sortBy</code> functions that work on collection types for this purpose. An example using an array of pairs: |
|||
<syntaxhighlight lang="fsharp">let persons = [| ("Joe", 120); ("foo", 31); ("bar", 51) |] |
|||
Array.sortInPlaceBy fst persons |
|||
printfn "%A" persons</syntaxhighlight> |
|||
Output: |
|||
WRITE (*,"(2A6)") rcc |
|||
<pre>[|("Joe", 120); ("bar", 51); ("foo", 31)|]</pre> |
|||
END PROGRAM EXAMPLE</lang> |
|||
An example using a list of records: |
|||
<syntaxhighlight lang="fsharp">type Person = { name:string; id:int } |
|||
let persons2 = [{name="Joe"; id=120}; {name="foo"; id=31}; {name="bar"; id=51}] |
|||
let sorted = List.sortBy (fun p -> p.id) persons2 |
|||
for p in sorted do printfn "%A" p</syntaxhighlight> |
|||
Output: |
|||
<pre>{name = "foo"; |
|||
id = 31;} |
|||
{name = "bar"; |
|||
id = 51;} |
|||
{name = "Joe"; |
|||
id = 120;}</pre> |
|||
=={{header|Factor}}== |
|||
This is essentially the same as [[Sorting Using a Custom Comparator]]. |
|||
<syntaxhighlight lang="factor">TUPLE: example-pair name value ; |
|||
: sort-by-name ( seq -- seq' ) [ [ name>> ] compare ] sort ;</syntaxhighlight> |
|||
( scratchpad ) { T{ example-pair f "omega" "a" } T{ example-pair f "gamma" "q" } T{ example-pair f "alpha" "z" } } sort-by-name . |
|||
{ |
|||
T{ example-pair { name "alpha" } { value "z" } } |
|||
T{ example-pair { name "gamma" } { value "q" } } |
|||
T{ example-pair { name "omega" } { value "a" } } |
|||
} |
|||
=={{header|Fantom}}== |
|||
Any object can be sorted as needed by passing an appropriate block to the 'sort' method. |
|||
<syntaxhighlight lang="fantom"> |
|||
class Pair // create a composite structure |
|||
{ |
|||
Str name |
|||
Str value |
|||
new make (Str name, Str value) |
|||
{ |
|||
this.name = name |
|||
this.value = value |
|||
} |
|||
override Str toStr () |
|||
{ |
|||
"(Pair: $name, $value)" |
|||
} |
|||
} |
|||
class Main |
|||
{ |
|||
public static Void main () |
|||
{ |
|||
// samples |
|||
pairs := [Pair("Fantom", "OO"), Pair("Clojure", "Functional"), Pair("Java", "OO") ] |
|||
sorted := pairs.dup // make a copy of original list |
|||
sorted.sort |Pair a, Pair b -> Int| // sort using custom comparator |
|||
{ |
|||
a.name <=> b.name |
|||
} |
|||
echo ("Started with : " + pairs.join(" ")) |
|||
echo ("Finished with: " + sorted.join(" ")) |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
=={{header|Fortran}}== |
|||
{{works with|Fortran|90 and later}} |
|||
Standard Fortran has no built-in sort function although some compilers add them. The following example uses an insertion sort. |
|||
<syntaxhighlight lang="fortran">PROGRAM EXAMPLE |
|||
IMPLICIT NONE |
|||
TYPE Pair |
|||
CHARACTER(6) :: name |
|||
CHARACTER(1) :: value |
|||
END TYPE Pair |
|||
TYPE(Pair) :: rcc(10), temp |
|||
INTEGER :: i, j |
|||
rcc(1) = Pair("Black", "0") |
|||
rcc(2) = Pair("Brown", "1") |
|||
rcc(3) = Pair("Red", "2") |
|||
rcc(4) = Pair("Orange", "3") |
|||
rcc(5) = Pair("Yellow", "4") |
|||
rcc(6) = Pair("Green", "5") |
|||
rcc(7) = Pair("Blue", "6") |
|||
rcc(8) = Pair("Violet", "7") |
|||
rcc(9) = Pair("Grey", "8") |
|||
rcc(10) = Pair("White", "9") |
|||
DO i = 2, SIZE(rcc) |
|||
j = i - 1 |
|||
temp = rcc(i) |
|||
DO WHILE (j>=1 .AND. LGT(rcc(j)%name, temp%name)) |
|||
rcc(j+1) = rcc(j) |
|||
j = j - 1 |
|||
END DO |
|||
rcc(j+1) = temp |
|||
END DO |
|||
WRITE (*,"(2A6)") rcc |
|||
END PROGRAM EXAMPLE</syntaxhighlight> |
|||
Output |
Output |
||
Black 0 |
Black 0 |
||
Line 406: | Line 2,036: | ||
White 9 |
White 9 |
||
Yellow 4 |
Yellow 4 |
||
=={{header|FreeBASIC}}== |
|||
<syntaxhighlight lang="freebasic">' FB 1.05.0 Win64 |
|||
Type Pair |
|||
As String name, value |
|||
Declare Constructor(name_ As String, value_ As String) |
|||
Declare Operator Cast() As String |
|||
End Type |
|||
Constructor Pair(name_ As String, value_ As String) |
|||
name = name_ |
|||
value = value_ |
|||
End Constructor |
|||
Operator Pair.Cast() As String |
|||
Return "[" + name + ", " + value + "]" |
|||
End Operator |
|||
' selection sort, quick enough for sorting small number of pairs |
|||
Sub sortPairsByName(p() As Pair) |
|||
Dim As Integer i, j, m |
|||
For i = LBound(p) To UBound(p) - 1 |
|||
m = i |
|||
For j = i + 1 To UBound(p) |
|||
If p(j).name < p(m).name Then m = j |
|||
Next j |
|||
If m <> i Then Swap p(i), p(m) |
|||
Next i |
|||
End Sub |
|||
Dim As Pair pairs(1 To 4) = _ |
|||
{ _ |
|||
Pair("grass", "green"), _ |
|||
Pair("snow", "white" ), _ |
|||
Pair("sky", "blue"), _ |
|||
Pair("cherry", "red") _ |
|||
} |
|||
Print "Before sorting :" |
|||
For i As Integer = 1 To 4 |
|||
Print Tab(3); pairs(i) |
|||
Next |
|||
sortPairsByName pairs() |
|||
Print |
|||
Print "After sorting by name :" |
|||
For i As Integer = 1 To 4 |
|||
Print Tab(3); pairs(i) |
|||
Next |
|||
Print |
|||
Print "Press any key to quit" |
|||
Sleep</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Before sorting : |
|||
[grass, green] |
|||
[snow, white] |
|||
[sky, blue] |
|||
[cherry, red] |
|||
After sorting by name : |
|||
[cherry, red] |
|||
[grass, green] |
|||
[sky, blue] |
|||
[snow, white] |
|||
</pre> |
|||
=={{header|Frink}}== |
|||
Frink's <CODE>lexicalCompare[a, b, language]</CODE> function can sort strings in a lexicographically correct way for many human languages by specifying a language specifier like "da" for Danish. This allows sort routines to magically work correctly for many human languages. |
|||
<syntaxhighlight lang="frink">class Pair |
|||
{ |
|||
var name |
|||
var value |
|||
new[name is string, value is string] := |
|||
{ |
|||
this.name = name |
|||
this.value = value |
|||
} |
|||
} |
|||
a = [new Pair["one", "1"], new Pair["two", "2"], new Pair["three", "3"]] |
|||
sort[a, {|a,b| lexicalCompare[a.name, b.name]}] |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre>[Pair |
|||
{ |
|||
name = one |
|||
value = 1 |
|||
} |
|||
, Pair |
|||
{ |
|||
name = three |
|||
value = 3 |
|||
} |
|||
, Pair |
|||
{ |
|||
name = two |
|||
value = 2 |
|||
} |
|||
] |
|||
</pre> |
|||
=={{header|Fōrmulæ}}== |
|||
{{FormulaeEntry|page=https://formulae.org/?script=examples/Sort_an_array_of_composite_structures}} |
|||
'''Solution''' |
|||
In the following example, it is assumed that the key is the first element of each pair. |
|||
[[File:Fōrmulæ - Sort an array of composite structures 01.png]] |
|||
[[File:Fōrmulæ - Sort an array of composite structures 02.png]] |
|||
=={{header|Go}}== |
|||
<syntaxhighlight lang="go">package main |
|||
import ( |
|||
"fmt" |
|||
"sort" |
|||
) |
|||
type pair struct { |
|||
name, value string |
|||
} |
|||
type csArray []pair |
|||
// three methods satisfy sort.Interface |
|||
func (a csArray) Less(i, j int) bool { return a[i].name < a[j].name } |
|||
func (a csArray) Len() int { return len(a) } |
|||
func (a csArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] } |
|||
var x = csArray{ |
|||
pair{"joe", "120"}, |
|||
pair{"foo", "31"}, |
|||
pair{"bar", "251"}, |
|||
} |
|||
func main() { |
|||
sort.Sort(x) |
|||
for _, p := range x { |
|||
fmt.Printf("%5s: %s\n", p.name, p.value) |
|||
} |
|||
}</syntaxhighlight> |
|||
=={{header|Groovy}}== |
=={{header|Groovy}}== |
||
< |
<syntaxhighlight lang="groovy">class Holiday { |
||
def date |
def date |
||
def name |
def name |
||
Line 432: | Line 2,212: | ||
holidays.sort { x, y -> x.date <=> y.date } |
holidays.sort { x, y -> x.date <=> y.date } |
||
holidays.each { println it }</ |
holidays.each { println it }</syntaxhighlight> |
||
Output: |
Output: |
||
Line 451: | Line 2,231: | ||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
<syntaxhighlight lang="haskell">import Data.List |
|||
import Data.Function (on) |
|||
data Person = P String Int deriving Eq |
|||
data Person = |
|||
P String |
|||
show (P name val) = "Person "++name++" with value "++(show val) |
|||
Int |
|||
instance Ord Person where |
|||
deriving (Eq) |
|||
compare (P n1 _) (P n2 _) = compare n1 n2 |
|||
instance Show Person where |
|||
people = [(P "Joe" 12), (P "Bob" 8), (P "Alice" 9), (P "Harry" 2)] |
|||
show (P name val) = "Person " ++ name ++ " with value " ++ show val |
|||
sortedPeople = sort people |
|||
sortedPeopleByVal = sortBy (\(P _ v1) (P _ v2)->compare v1 v2) people |
|||
instance Ord Person where |
|||
compare (P a _) (P b _) = compare a b |
|||
pVal :: Person -> Int |
|||
pVal (P _ x) = x |
|||
people :: [Person] |
|||
people = [P "Joe" 12, P "Bob" 8, P "Alice" 9, P "Harry" 2] |
|||
main :: IO () |
|||
main = do |
|||
mapM_ print $ sort people |
|||
putStrLn [] |
|||
mapM_ print $ sortBy (on compare pVal) people</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>Person Alice with value 9 |
|||
Person Bob with value 8 |
|||
Person Harry with value 2 |
|||
Person Joe with value 12 |
|||
Person Harry with value 2 |
|||
Person Bob with value 8 |
|||
Person Alice with value 9 |
|||
Person Joe with value 12</pre> |
|||
More generally, '''sortBy''' takes any (a -> a -> Ordering) function as its first argument. A function of this kind can be derived from a simpler (b -> a) function using the higher order '''comparing''' function. |
|||
To sort a list of triples by the third element, for example: |
|||
<syntaxhighlight lang="haskell">import Data.Ord (comparing) |
|||
import Data.List (sortBy) |
|||
xs :: [(String, String, Int)] |
|||
xs = |
|||
zip3 |
|||
(words "Richard John Marvin Alan Maurice James") |
|||
(words "Hamming McCarthy Minskey Perlis Wilkes Wilkinson") |
|||
[1915, 1927, 1926, 1922, 1913, 1919] |
|||
main :: IO () |
|||
main = mapM_ print $ sortBy (comparing (\(_, _, y) -> y)) xs</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>("Maurice","Wilkes",1913) |
|||
("Richard","Hamming",1915) |
|||
("James","Wilkinson",1919) |
|||
("Alan","Perlis",1922) |
|||
("Marvin","Minskey",1926) |
|||
("John","McCarthy",1927)</pre> |
|||
=={{header|Icon}} and {{header|Unicon}}== |
|||
The built-in procedure sortf will sort a list by the field in a records. |
|||
<syntaxhighlight lang="icon">record star(name,HIP) |
|||
procedure main() |
|||
Ori := [ star("Betelgeuse",27989), |
|||
star("Rigel",24436), |
|||
star("Belatrix", 25336), |
|||
star("Alnilam",26311) ] |
|||
write("Some Orion stars by HIP#") |
|||
every write( (x := !sortf(Ori,2)).name, " HIP ",x.HIP) |
|||
end</syntaxhighlight> |
|||
Sample output:<pre>Some Orion stars by HIP# |
|||
Rigel HIP 24436 |
|||
Belatrix HIP 25336 |
|||
Alnilam HIP 26311 |
|||
Betelgeuse HIP 27989</pre> |
|||
=={{header|J}}== |
=={{header|J}}== |
||
The function<tt> /: </tt>sorts |
The function<tt> /: </tt>sorts anything (its left argument) based on the keys supplied in its right argument. For example: |
||
<syntaxhighlight lang="j"> names =: ;: 'Perlis Wilkes Hamming Minsky Wilkinson McCarthy' |
|||
values=: ;: 'Alan Maurice Richard Marvin James John' |
|||
pairs =: values ,. names |
|||
pairs /: names |
|||
+-------+---------+ |
|||
|Richard|Hamming | |
|||
+-------+---------+ |
|||
|John |McCarthy | |
|||
+-------+---------+ |
|||
|Marvin |Minsky | |
|||
+-------+---------+ |
|||
|Alan |Perlis | |
|||
+-------+---------+ |
|||
|Maurice|Wilkes | |
|||
+-------+---------+ |
|||
|James |Wilkinson| |
|||
+-------+---------+</syntaxhighlight> |
|||
Alternatively, J's cross operator will use the same values for both the left and right arguments for /: but, in this case, /:~ is not desirable because that would have us sorting on the values (the first column) and only using the second column for equal names (none of which appear, here). |
|||
names =: ;: 'Perlis Wilkes Hamming Minsky Wilkinson McCarthy' |
|||
values=: ;: 'Alan Maurice Richard Marvin James John' |
|||
pairs =: values ,. names |
|||
pairs /: names |
|||
+-------+---------+ |
|||
|Richard|Hamming | |
|||
+-------+---------+ |
|||
|John |McCarthy | |
|||
+-------+---------+ |
|||
|Marvin |Minsky | |
|||
+-------+---------+ |
|||
|Alan |Perlis | |
|||
+-------+---------+ |
|||
|Maurice|Wilkes | |
|||
+-------+---------+ |
|||
|James |Wilkinson| |
|||
+-------+---------+ |
|||
=={{header|Java}}== |
=={{header|Java}}== |
||
< |
<syntaxhighlight lang="java">import java.util.Arrays; |
||
import java.util.Comparator; |
import java.util.Comparator; |
||
Line 518: | Line 2,371: | ||
}); |
}); |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
Output: |
Output: |
||
<pre>00-01 Avalanche |
<pre>00-01 Avalanche |
||
Line 531: | Line 2,384: | ||
99-00 Devils</pre> |
99-00 Devils</pre> |
||
In Java 8, we can write the above using a lambda: |
|||
=={{header|Mathematica}}== |
|||
{{works with|Java|8+}} |
|||
<lang Mathematica> |
|||
<syntaxhighlight lang="java"> public static void sortByName(Pair[] pairs) { |
|||
events = {{"2009-12-25", "Christmas Day"}, {"2009-04-22", |
|||
Arrays.sort(pairs, (p1, p2) -> p1.name.compareTo(p2.name)); |
|||
}</syntaxhighlight> |
|||
We can further use <code>Comparator.comparing()</code> to construct the comparator from a "key" function: |
|||
{{works with|Java|8+}} |
|||
<syntaxhighlight lang="java"> public static void sortByName(Pair[] pairs) { |
|||
Arrays.sort(pairs, Comparator.comparing(p -> p.name)); |
|||
}</syntaxhighlight> |
|||
=={{header|JavaScript}}== |
|||
===ES5=== |
|||
<syntaxhighlight lang="javascript">var arr = [ |
|||
{id: 3, value: "foo"}, |
|||
{id: 2, value: "bar"}, |
|||
{id: 4, value: "baz"}, |
|||
{id: 1, value: 42}, |
|||
{id: 5, something: "another string"} // Works with any object declaring 'id' as a number. |
|||
]; |
|||
arr = arr.sort(function(a, b) {return a.id - b.id}); // Sort with comparator checking the id. |
|||
</syntaxhighlight> |
|||
===ES6=== |
|||
<syntaxhighlight lang="javascript">(() => { |
|||
'use strict'; |
|||
// GENERIC FUNCTIONS FOR COMPARISONS |
|||
// compare :: a -> a -> Ordering |
|||
const compare = (a, b) => a < b ? -1 : (a > b ? 1 : 0); |
|||
// on :: (b -> b -> c) -> (a -> b) -> a -> a -> c |
|||
const on = (f, g) => (a, b) => f(g(a), g(b)); |
|||
// flip :: (a -> b -> c) -> b -> a -> c |
|||
const flip = f => (a, b) => f.apply(null, [b, a]); |
|||
// arrayCopy :: [a] -> [a] |
|||
const arrayCopy = (xs) => xs.slice(0); |
|||
// show :: a -> String |
|||
const show = x => JSON.stringify(x, null, 2); |
|||
// TEST |
|||
const xs = [{ |
|||
name: 'Shanghai', |
|||
pop: 24.2 |
|||
}, { |
|||
name: 'Karachi', |
|||
pop: 23.5 |
|||
}, { |
|||
name: 'Beijing', |
|||
pop: 21.5 |
|||
}, { |
|||
name: 'Sao Paulo', |
|||
pop: 24.2 |
|||
}, { |
|||
name: 'Dhaka', |
|||
pop: 17.0 |
|||
}, { |
|||
name: 'Delhi', |
|||
pop: 16.8 |
|||
}, { |
|||
name: 'Lagos', |
|||
pop: 16.1 |
|||
}] |
|||
// population :: Dictionary -> Num |
|||
const population = x => x.pop; |
|||
// name :: Dictionary -> String |
|||
const name = x => x.name; |
|||
return show({ |
|||
byPopulation: arrayCopy(xs) |
|||
.sort(on(compare, population)), |
|||
byDescendingPopulation: arrayCopy(xs) |
|||
.sort(on(flip(compare), population)), |
|||
byName: arrayCopy(xs) |
|||
.sort(on(compare, name)), |
|||
byDescendingName: arrayCopy(xs) |
|||
.sort(on(flip(compare), name)) |
|||
}); |
|||
})();</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>{ |
|||
"byPopulation": [ |
|||
{ |
|||
"name": "Lagos", |
|||
"pop": 16.1 |
|||
}, |
|||
{ |
|||
"name": "Delhi", |
|||
"pop": 16.8 |
|||
}, |
|||
{ |
|||
"name": "Dhaka", |
|||
"pop": 17 |
|||
}, |
|||
{ |
|||
"name": "Beijing", |
|||
"pop": 21.5 |
|||
}, |
|||
{ |
|||
"name": "Karachi", |
|||
"pop": 23.5 |
|||
}, |
|||
{ |
|||
"name": "Shanghai", |
|||
"pop": 24.2 |
|||
}, |
|||
{ |
|||
"name": "Sao Paulo", |
|||
"pop": 24.2 |
|||
} |
|||
], |
|||
"byDescendingPopulation": [ |
|||
{ |
|||
"name": "Shanghai", |
|||
"pop": 24.2 |
|||
}, |
|||
{ |
|||
"name": "Sao Paulo", |
|||
"pop": 24.2 |
|||
}, |
|||
{ |
|||
"name": "Karachi", |
|||
"pop": 23.5 |
|||
}, |
|||
{ |
|||
"name": "Beijing", |
|||
"pop": 21.5 |
|||
}, |
|||
{ |
|||
"name": "Dhaka", |
|||
"pop": 17 |
|||
}, |
|||
{ |
|||
"name": "Delhi", |
|||
"pop": 16.8 |
|||
}, |
|||
{ |
|||
"name": "Lagos", |
|||
"pop": 16.1 |
|||
} |
|||
], |
|||
"byName": [ |
|||
{ |
|||
"name": "Beijing", |
|||
"pop": 21.5 |
|||
}, |
|||
{ |
|||
"name": "Delhi", |
|||
"pop": 16.8 |
|||
}, |
|||
{ |
|||
"name": "Dhaka", |
|||
"pop": 17 |
|||
}, |
|||
{ |
|||
"name": "Karachi", |
|||
"pop": 23.5 |
|||
}, |
|||
{ |
|||
"name": "Lagos", |
|||
"pop": 16.1 |
|||
}, |
|||
{ |
|||
"name": "Sao Paulo", |
|||
"pop": 24.2 |
|||
}, |
|||
{ |
|||
"name": "Shanghai", |
|||
"pop": 24.2 |
|||
} |
|||
], |
|||
"byDescendingName": [ |
|||
{ |
|||
"name": "Shanghai", |
|||
"pop": 24.2 |
|||
}, |
|||
{ |
|||
"name": "Sao Paulo", |
|||
"pop": 24.2 |
|||
}, |
|||
{ |
|||
"name": "Lagos", |
|||
"pop": 16.1 |
|||
}, |
|||
{ |
|||
"name": "Karachi", |
|||
"pop": 23.5 |
|||
}, |
|||
{ |
|||
"name": "Dhaka", |
|||
"pop": 17 |
|||
}, |
|||
{ |
|||
"name": "Delhi", |
|||
"pop": 16.8 |
|||
}, |
|||
{ |
|||
"name": "Beijing", |
|||
"pop": 21.5 |
|||
} |
|||
] |
|||
}</pre> |
|||
=={{header|jq}}== |
|||
In this section we will focus on JSON objects since the task description mentions keys. As an example, we will use this array: |
|||
<syntaxhighlight lang="jq">def example: |
|||
[ |
|||
{"name": "Joe", "value": 3}, |
|||
{"name": "Bill", "value": 4}, |
|||
{"name": "Alice", "value": 20}, |
|||
{"name": "Harry", "value": 3} |
|||
];</syntaxhighlight> |
|||
====Using sort_by builtin ==== |
|||
jq's sort_by builtin can be used to sort by the value of a given key (whether or not it is a string), so we will first use that. |
|||
<syntaxhighlight lang="jq"># To sort the array: |
|||
# example | sort_by(.name) |
|||
# To abbreviate the results, we will just show the names after sorting: |
|||
example | sort_by(.name) | map( .name )</syntaxhighlight> |
|||
{{Out}} |
|||
$ jq -n -c -f Sort_an_array_of_composite_structures.jq |
|||
["Alice","Bill","Harry","Joe"] |
|||
====Using quicksort(cmp)==== |
|||
sort_by(f) can easily be implemented using quicksort(cmp) as defined at [[Sorting_Using_a_Custom_Comparator#jq]] as follows: |
|||
<syntaxhighlight lang="jq">def quicksort_by(f): quicksort( (.[0]|f) <= (.[1]|f) );</syntaxhighlight> |
|||
'''Example''': |
|||
<syntaxhighlight lang="jq">example | quicksort_by(.name) | map( .name )</syntaxhighlight> |
|||
{{Out}} |
|||
As above. |
|||
=={{header|Julia}}== |
|||
{{works with|Julia|0.6}} |
|||
<syntaxhighlight lang="julia">lst = Pair[Pair("gold", "shiny"), |
|||
Pair("neon", "inert"), |
|||
Pair("sulphur", "yellow"), |
|||
Pair("iron", "magnetic"), |
|||
Pair("zebra", "striped"), |
|||
Pair("star", "brilliant"), |
|||
Pair("apple", "tasty"), |
|||
Pair("ruby", "red"), |
|||
Pair("dice", "random"), |
|||
Pair("coffee", "stimulating"), |
|||
Pair("book", "interesting")] |
|||
println("The original list: \n - ", join(lst, "\n - ")) |
|||
sort!(lst; by=first) |
|||
println("\nThe list, sorted by name: \n - ", join(lst, "\n - ")) |
|||
sort!(lst; by=last) |
|||
println("\nThe list, sorted by value: \n - ", join(lst, "\n - "))</syntaxhighlight> |
|||
{{out}} |
|||
<pre>The original list: |
|||
- "gold"=>"shiny" |
|||
- "neon"=>"inert" |
|||
- "sulphur"=>"yellow" |
|||
- "iron"=>"magnetic" |
|||
- "zebra"=>"striped" |
|||
- "star"=>"brilliant" |
|||
- "apple"=>"tasty" |
|||
- "ruby"=>"red" |
|||
- "dice"=>"random" |
|||
- "coffee"=>"stimulating" |
|||
- "book"=>"interesting" |
|||
The list, sorted by name: |
|||
- "apple"=>"tasty" |
|||
- "book"=>"interesting" |
|||
- "coffee"=>"stimulating" |
|||
- "dice"=>"random" |
|||
- "gold"=>"shiny" |
|||
- "iron"=>"magnetic" |
|||
- "neon"=>"inert" |
|||
- "ruby"=>"red" |
|||
- "star"=>"brilliant" |
|||
- "sulphur"=>"yellow" |
|||
- "zebra"=>"striped" |
|||
The list, sorted by value: |
|||
- "star"=>"brilliant" |
|||
- "neon"=>"inert" |
|||
- "book"=>"interesting" |
|||
- "iron"=>"magnetic" |
|||
- "dice"=>"random" |
|||
- "ruby"=>"red" |
|||
- "gold"=>"shiny" |
|||
- "coffee"=>"stimulating" |
|||
- "zebra"=>"striped" |
|||
- "apple"=>"tasty" |
|||
- "sulphur"=>"yellow"</pre> |
|||
=={{header|Kotlin}}== |
|||
<syntaxhighlight lang="scala">// version 1.1 |
|||
data class Employee(val name: String, var category: String) : Comparable<Employee> { |
|||
override fun compareTo(other: Employee) = this.name.compareTo(other.name) |
|||
} |
|||
fun main(args: Array<String>) { |
|||
val employees = arrayOf( |
|||
Employee("David", "Manager"), |
|||
Employee("Alice", "Sales"), |
|||
Employee("Joanna", "Director"), |
|||
Employee("Henry", "Admin"), |
|||
Employee("Tim", "Sales"), |
|||
Employee("Juan", "Admin") |
|||
) |
|||
employees.sort() |
|||
for ((name, category) in employees) println("${name.padEnd(6)} : $category") |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Alice : Sales |
|||
David : Manager |
|||
Henry : Admin |
|||
Joanna : Director |
|||
Juan : Admin |
|||
Tim : Sales |
|||
</pre> |
|||
=={{header|Lambdatalk}}== |
|||
<syntaxhighlight lang="scheme"> |
|||
{def H.sort |
|||
{def H.sort.i |
|||
{lambda {:f :x :a} |
|||
{if {A.empty? :a} |
|||
then {A.new :x} |
|||
else {if {:f :x {A.first :a}} |
|||
then {A.addfirst! :x :a} |
|||
else {A.addfirst! {A.first :a} {H.sort.i :f :x {A.rest :a}}} }}}} |
|||
{def H.sort.r |
|||
{lambda {:f :a1 :a2} |
|||
{if {A.empty? :a1} |
|||
then :a2 |
|||
else {H.sort.r :f {A.rest :a1} {H.sort.i :f {A.first :a1} :a2}} }}} |
|||
{lambda {:f :a} |
|||
{H.sort.r :f :a {A.new}} }} |
|||
-> H.sort |
|||
{def H.display |
|||
{lambda {:h} |
|||
{table |
|||
{tr {S.map {{lambda {:h :i} {td {car {A.get :i :h}}}} :h} |
|||
{S.serie 0 {- {A.length :h} 1}}}} |
|||
{tr {S.map {{lambda {:h :i} {td {cdr {A.get :i :h}}}} :h} |
|||
{S.serie 0 {- {A.length :h} 1}}}} |
|||
}}} |
|||
-> H.display |
|||
1) an array of pairs: |
|||
{def H {A.new {cons Joe 5531} |
|||
{cons Adam 2341} |
|||
{cons Bernie 122} |
|||
{cons Walter 1234} |
|||
{cons David 19}}} |
|||
-> H |
|||
2) display sorted by names: |
|||
{H.display |
|||
{H.sort {lambda {:a :b} {< {lexicographic {car :a} {car :b}} 0}} {H}}} |
|||
-> |
|||
Adam Bernie David Joe Walter |
|||
2341 122 19 5531 1234 |
|||
3) display sorted by values: |
|||
{H.display |
|||
{H.sort {lambda {:a :b} {< {cdr :a} {cdr :b}}} {H}}} |
|||
-> |
|||
David Bernie Walter Adam Joe |
|||
19 122 1234 2341 5531 |
|||
</syntaxhighlight> |
|||
=={{header|Liberty BASIC}}== |
|||
NB LB sorts in a non standard order. See http://libertybasicbugs.wikispaces.com/Comparison+of+characters+and+strings+is+not+ASCII+based |
|||
<br> |
|||
The method used here to simulate a compound structure can only hold pairs of terms, since LB arrays ar 1D or 2D. More complicated associated arrays could be stored in delimiter-separated string arrays. |
|||
<syntaxhighlight lang="lb"> |
|||
N =20 |
|||
dim IntArray$( N, 2) |
|||
print "Original order" |
|||
for i =1 to N |
|||
name$ =mid$( "SortArrayOfCompositeStructures", int( 25 *rnd( 1)), 1 +int( 4 *rnd( 1))) |
|||
IntArray$( i, 1) =name$ |
|||
print name$, |
|||
t$ =str$( int( 1000 *rnd( 1))) |
|||
IntArray$( i, 2) =t$ |
|||
print t$ |
|||
next i |
|||
sort IntArray$(), 1, N, 1 |
|||
print "Sorted by name" ' ( we specified column 1) |
|||
for i =1 to N |
|||
print IntArray$( i, 1), IntArray$( i, 2) |
|||
next i |
|||
</syntaxhighlight> |
|||
=={{header|Lua}}== |
|||
<syntaxhighlight lang="lua">function sorting( a, b ) |
|||
return a[1] < b[1] |
|||
end |
|||
tab = { {"C++", 1979}, {"Ada", 1983}, {"Ruby", 1995}, {"Eiffel", 1985} } |
|||
table.sort( tab, sorting ) |
|||
for _, v in ipairs( tab ) do |
|||
print( unpack(v) ) |
|||
end</syntaxhighlight> |
|||
=={{header|M2000 Interpreter}}== |
|||
Checkit do exactly task need: make pairs as groups of name and value_ (note _ used because value used for other purpose in a group definition), make a Quick group from class Quick, pass a new lambda for comparing items, and pass array with objects to sort in quicksort function of Quick group. Keys no need to be unique. |
|||
Checkit2 make an inventory with keys and values, then sort them (internal use Quicksort, and keys must be unique) |
|||
Checkit3 same as CheckIt3 except values are groups, which now have only a x as value, but we can add more. |
|||
<syntaxhighlight lang="m2000 interpreter"> |
|||
Module CheckIt { |
|||
Flush ' empty stack of values |
|||
Class Quick { |
|||
Private: |
|||
partition=lambda-> { |
|||
Read &A(), p, r : i = p-1 : x=A(r) |
|||
For j=p to r-1 {If .LE(A(j), x) Then i++:Swap A(i),A(j) |
|||
} : Swap A(i+1), A(r) : Push i+2, i |
|||
} |
|||
Public: |
|||
LE=Lambda->Number<=Number |
|||
Module ForStrings { |
|||
.partition<=lambda-> { |
|||
Read &a$(), p, r : i = p-1 : x$=a$(r) |
|||
For j=p to r-1 {If a$(j)<= x$ Then i++:Swap a$(i),a$(j) |
|||
} : Swap a$(i+1), a$(r) : Push i+2, i |
|||
} |
|||
} |
|||
Function quicksort { |
|||
Read ref$ |
|||
{ |
|||
loop : If Stackitem() >= Stackitem(2) Then Drop 2 : if empty then {Break} else continue |
|||
over 2,2 : call .partition(ref$) :shift 3 |
|||
} |
|||
} |
|||
} |
|||
Quick=Quick() |
|||
Quick.LE=lambda (a, b)->{ |
|||
=a.name$<=b.name$ |
|||
} |
|||
Data "Joe", 5531 |
|||
Data "Adam", 2341 |
|||
Data "Bernie", 122 |
|||
Data "Walter", 1234 |
|||
Data "David", 19 |
|||
Class pair { |
|||
name$ |
|||
value_ |
|||
} |
|||
Document Doc$={Unsorted Pairs: |
|||
} |
|||
Dim A(1 to 5)=pair() |
|||
For i=1 to 5 { |
|||
For A(i) { |
|||
Read .name$, .value_ |
|||
Doc$=Format$("{0}, {1}", .name$, .value_)+{ |
|||
} |
|||
} |
|||
} |
|||
Call Quick.quicksort(&A(),1, 5) |
|||
Doc$={ |
|||
Sorted Pairs |
|||
} |
|||
k=Each(A()) |
|||
While k { |
|||
getone=array(k) |
|||
For getone { |
|||
Doc$=Format$("{0}, {1}", .name$, .value_)+{ |
|||
} |
|||
} |
|||
} |
|||
Report Doc$ |
|||
Clipboard Doc$ |
|||
} |
|||
Checkit |
|||
module Checkit2 { |
|||
Inventory Alfa="Joe":=5531, "Adam":=2341, "Bernie":=122 |
|||
Append Alfa, "Walter":=1234, "David":=19 |
|||
Sort Alfa |
|||
k=Each(Alfa) |
|||
While k { |
|||
Print eval$(Alfa, k^), Eval(k) |
|||
} |
|||
} |
|||
Checkit2 |
|||
module Checkit3 { |
|||
class any { |
|||
x |
|||
class: |
|||
Module any (.x) {} |
|||
} |
|||
Inventory Alfa="Joe":=any(5531), "Adam":=any(2341), "Bernie":=any(122) |
|||
Append Alfa, "Walter":=any(1234), "David":=any(19) |
|||
Sort Alfa |
|||
k=Each(Alfa) |
|||
While k { |
|||
\\ k^ is the index number by k cursor |
|||
\\ Alfa("joe") return object |
|||
\\ Alfa(0!) return first element object |
|||
\\ Alfa(k^!) return (k^) objext |
|||
Print eval$(Alfa, k^), Alfa(k^!).x |
|||
} |
|||
} |
|||
Checkit3 |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
From Checkit (checkit2 and checkit3 show exact sorted inventories) |
|||
<pre> |
|||
Unsorted Pairs: |
|||
Joe, 5531 |
|||
Adam, 2341 |
|||
Bernie, 122 |
|||
Walter, 1234 |
|||
David, 19 |
|||
Sorted Pairs |
|||
Adam, 2341 |
|||
Bernie, 122 |
|||
David, 19 |
|||
Joe, 5531 |
|||
Walter, 1234 |
|||
</pre> |
|||
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
|||
<syntaxhighlight lang="mathematica">events = {{"2009-12-25", "Christmas Day"}, {"2009-04-22", |
|||
"Earth Day"}, {"2009-09-07", "Labor Day"}, {"2009-07-04", |
"Earth Day"}, {"2009-09-07", "Labor Day"}, {"2009-07-04", |
||
"Independence Day"}, {"2009-10-31", "Halloween"}, {"2009-05-25", |
"Independence Day"}, {"2009-10-31", "Halloween"}, {"2009-05-25", |
||
Line 545: | Line 2,942: | ||
name = 2; |
name = 2; |
||
SortBy[events, #[[name]] &] // Grid |
SortBy[events, #[[name]] &] // Grid |
||
SortBy[events, #[[date]] &] // Grid |
SortBy[events, #[[date]] &] // Grid</syntaxhighlight> |
||
</lang> |
|||
gives back: |
gives back: |
||
<syntaxhighlight lang="mathematica">2009-12-25 Christmas Day |
|||
<lang Mathematica> |
|||
2009-12-25 Christmas Day |
|||
2009-04-22 Earth Day |
2009-04-22 Earth Day |
||
2009-10-31 Halloween |
2009-10-31 Halloween |
||
Line 578: | Line 2,973: | ||
2009-11-26 Thanksgiving |
2009-11-26 Thanksgiving |
||
2009-12-25 Christmas Day |
2009-12-25 Christmas Day |
||
2009-12-31 New Year's Eve |
2009-12-31 New Year's Eve</syntaxhighlight> |
||
</lang> |
|||
=={{header|MAXScript}}== |
=={{header|MAXScript}}== |
||
<syntaxhighlight lang="maxscript">fn keyCmp comp1 comp2 = |
|||
( |
|||
case of |
|||
( |
|||
(comp1[1] > comp2[1]): 1 |
|||
(comp1[1] < comp2[1]): -1 |
|||
default: 0 |
|||
) |
|||
) |
|||
people = #(#("joe", 39), #("dave", 37), #("bob", 42)) |
|||
qsort people keyCmp |
|||
print people</syntaxhighlight> |
|||
=={{header|NetRexx}}== |
|||
<syntaxhighlight lang="netrexx">/* NetRexx */ |
|||
options replace format comments java crossref symbols nobinary |
|||
-- ============================================================================= |
|||
class RSortCompsiteStructure public |
|||
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
method main(args = String[]) public static |
|||
places = [ - |
|||
PairBean('London', 'UK'), PairBean('New York', 'US') - |
|||
, PairBean('Boston', 'US'), PairBean('Washington', 'US') - |
|||
, PairBean('Washington', 'UK'), PairBean("Birmingham", 'US') - |
|||
, PairBean("Birmingham", 'UK'), PairBean("Boston", 'UK') - |
|||
] |
|||
say displayArray(places) |
|||
Arrays.sort(places, PairComparator()) |
|||
say displayArray(places) |
|||
return |
|||
method displayArray(harry = PairBean[]) constant |
|||
disp = '' |
|||
loop elmt over harry |
|||
disp = disp','elmt |
|||
end elmt |
|||
return '['disp.substr(2)']' -- trim leading comma |
|||
-- ============================================================================= |
|||
class RSortCompsiteStructure.PairBean |
|||
properties indirect |
|||
name |
|||
value |
|||
method PairBean(name_, value_) public |
|||
setName(name_) |
|||
setValue(value_) |
|||
return |
|||
method toString() public returns String |
|||
return '('getName()','getValue()')' |
|||
-- ============================================================================= |
|||
class RSortCompsiteStructure.PairComparator implements Comparator |
|||
method compare(lft = Object, rgt = Object) public binary returns int |
|||
cRes = int |
|||
if lft <= RSortCompsiteStructure.PairBean, rgt <= RSortCompsiteStructure.PairBean then do |
|||
lName = String (RSortCompsiteStructure.PairBean lft).getName() |
|||
rName = String (RSortCompsiteStructure.PairBean rgt).getName() |
|||
cRes = lName.compareTo(rName) |
|||
if cRes == 0 then do |
|||
lVal = String (RSortCompsiteStructure.PairBean lft).getValue() |
|||
rVal = String (RSortCompsiteStructure.PairBean rgt).getValue() |
|||
cRes = lVal.compareTo(rVal) |
|||
end |
|||
end |
|||
else signal IllegalArgumentException('Arguments must be of type PairBean') |
|||
return cRes |
|||
</syntaxhighlight> |
|||
'''Output:''' |
|||
<pre> |
|||
[(London,UK),(New York,US),(Boston,US),(Washington,US),(Washington,UK),(Birmingham,US),(Birmingham,UK),(Boston,UK)] |
|||
[(Birmingham,UK),(Birmingham,US),(Boston,UK),(Boston,US),(London,UK),(New York,US),(Washington,UK),(Washington,US)] |
|||
</pre> |
|||
=={{header|Nim}}== |
|||
<syntaxhighlight lang="nim">import algorithm, sugar |
|||
var people = @{"joe": 120, "foo": 31, "bar": 51} |
|||
sort(people, (x,y) => cmp(x[0], y[0])) |
|||
echo people</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>@[("bar", 51), ("foo", 31), ("joe", 120)]</pre> |
|||
=={{header|Objeck}}== |
|||
<syntaxhighlight lang="objeck"> |
|||
use Collection; |
|||
class Entry implements Compare { |
|||
@name : String; |
|||
@value : Float; |
|||
New(name : String, value : Float) { |
|||
@name := name; |
|||
@value := value; |
|||
} |
|||
method : public : Compare(rhs : Compare) ~ Int { |
|||
return @name->Compare(rhs->As(Entry)->GetName()); |
|||
} |
|||
method : public : GetName() ~ String { |
|||
return @name; |
|||
} |
|||
method : public : HashID() ~ Int { |
|||
return @name->HashID(); |
|||
} |
|||
method : public : ToString() ~ String { |
|||
return "name={$@name}, value={$@value}"; |
|||
} |
|||
} |
|||
class Sorter { |
|||
function : Main(args : String[]) ~ Nil { |
|||
entries := CompareVector->New(); |
|||
entries->AddBack(Entry->New("Krypton", 83.798)); |
|||
entries->AddBack(Entry->New("Beryllium", 9.012182)); |
|||
entries->AddBack(Entry->New("Silicon", 28.0855)); |
|||
entries->AddBack(Entry->New("Cobalt", 58.933195)); |
|||
entries->AddBack(Entry->New("Selenium", 78.96)); |
|||
entries->AddBack(Entry->New("Germanium", 72.64)); |
|||
entries->Sort(); |
|||
each(i : entries) { |
|||
entries->Get(i)->As(Entry)->ToString()->PrintLine(); |
|||
}; |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
<pre> |
|||
name=Beryllium, value=9.12 |
|||
name=Cobalt, value=58.934 |
|||
name=Germanium, value=72.640 |
|||
name=Krypton, value=83.798 |
|||
name=Selenium, value=78.960 |
|||
name=Silicon, value=28.85 |
|||
</pre> |
|||
=={{header|Objective-C}}== |
=={{header|Objective-C}}== |
||
< |
<syntaxhighlight lang="objc">@interface Pair : NSObject { |
||
NSString *name; |
NSString *name; |
||
NSString *value; |
NSString *value; |
||
} |
} |
||
+( |
+(instancetype)pairWithName:(NSString *)n value:(NSString *)v; |
||
-( |
-(instancetype)initWithName:(NSString *)n value:(NSString *)v; |
||
-(NSString *)name; |
-(NSString *)name; |
||
-(NSString *)value; |
-(NSString *)value; |
||
Line 608: | Line 3,130: | ||
@implementation Pair |
@implementation Pair |
||
+( |
+(instancetype)pairWithName:(NSString *)n value:(NSString *)v { |
||
return |
return [[self alloc] initWithName:n value:v]; |
||
} |
} |
||
-( |
-(instancetype)initWithName:(NSString *)n value:(NSString *)v { |
||
if ((self = [super init])) { |
if ((self = [super init])) { |
||
name = |
name = n; |
||
value = |
value = v; |
||
} |
} |
||
return self; |
return self; |
||
} |
|||
-(void)dealloc { |
|||
[name release]; |
|||
[value release]; |
|||
[super dealloc]; |
|||
} |
} |
||
-(NSString *)name { return name; } |
-(NSString *)name { return name; } |
||
Line 631: | Line 3,148: | ||
int main() { |
int main() { |
||
@autoreleasepool { |
|||
NSArray *pairs = [NSArray arrayWithObjects: |
|||
NSArray *pairs = @[ |
|||
[Pair pairWithName:@"06-07" value:@"Ducks"], |
[Pair pairWithName:@"06-07" value:@"Ducks"], |
||
[Pair pairWithName:@"00-01" value:@"Avalanche"], |
[Pair pairWithName:@"00-01" value:@"Avalanche"], |
||
Line 641: | Line 3,160: | ||
[Pair pairWithName:@"99-00" value:@"Devils"], |
[Pair pairWithName:@"99-00" value:@"Devils"], |
||
[Pair pairWithName:@"07-08" value:@"Red Wings"], |
[Pair pairWithName:@"07-08" value:@"Red Wings"], |
||
[Pair pairWithName:@"08-09" value:@"Penguins"] |
[Pair pairWithName:@"08-09" value:@"Penguins"]]; |
||
nil]; |
|||
// optional 3rd arg: you can also specify a selector to compare the keys |
// optional 3rd arg: you can also specify a selector to compare the keys |
||
NSSortDescriptor *sd = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]; |
NSSortDescriptor *sd = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]; |
||
// it takes an array of sort descriptors, and it will be ordered by the |
// it takes an array of sort descriptors, and it will be ordered by the |
||
// first one, then if it's a tie by the second one, etc. |
// first one, then if it's a tie by the second one, etc. |
||
NSArray *sorted = [pairs sortedArrayUsingDescriptors: |
NSArray *sorted = [pairs sortedArrayUsingDescriptors:@[sd]]; |
||
NSLog(@"%@", sorted); |
|||
[NSArray arrayWithObject:sd]]; |
|||
NSLog(@"%@", sorted); |
|||
} |
|||
[sd release]; |
|||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
=={{header|OCaml}}== |
=={{header|OCaml}}== |
||
<syntaxhighlight lang="ocaml"># let people = [("Joe", 12); ("Bob", 8); ("Alice", 9); ("Harry", 2)];; |
|||
val people : (string * int) list = |
|||
[("Joe", 12); ("Bob", 8); ("Alice", 9); ("Harry", 2)] |
|||
# let sortedPeopleByVal = List.sort (fun (_, v1) (_, v2) -> compare v1 v2) people;; |
|||
val sortedPeopleByVal : (string * int) list = |
|||
[("Harry", 2); ("Bob", 8); ("Alice", 9); ("Joe", 12)]</syntaxhighlight> |
|||
=={{header|Oforth}}== |
|||
<syntaxhighlight lang="oforth">[["Joe",5531], ["Adam",2341], ["Bernie",122], ["David",19]] sortBy(#first) println</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
[[Adam, 2341], [Bernie, 122], [David, 19], [Joe, 5531]] |
|||
</pre> |
|||
=={{header|Ol}}== |
|||
<syntaxhighlight lang="scheme"> |
|||
(import (scheme char)) |
|||
(define (comp a b) |
|||
(string-ci<? (a 'name #f) (b 'name #f))) |
|||
(for-each print |
|||
(sort comp (list |
|||
{ 'name "David" |
|||
'value "Manager" } |
|||
{ 'name "Alice" |
|||
'value "Sales" } |
|||
{ 'name "Joanna" |
|||
'value "Director" } |
|||
{ 'name "Henry" |
|||
'value "Admin" } |
|||
{ 'name "Tim" |
|||
'value "Sales" } |
|||
{ 'name "Juan" |
|||
'value "Admin" }))) |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
#ff((name . Alice) (value . Sales)) |
|||
#ff((name . David) (value . Manager)) |
|||
#ff((name . Henry) (value . Admin)) |
|||
#ff((name . Joanna) (value . Director)) |
|||
#ff((name . Juan) (value . Admin)) |
|||
#ff((name . Tim) (value . Sales)) |
|||
</pre> |
|||
=={{header|ooRexx}}== |
|||
<syntaxhighlight lang="oorexx"> |
|||
a = .array~new |
|||
a~append(.pair~new("06-07", "Ducks")) |
|||
a~append(.pair~new("00-01", "Avalanche")) |
|||
a~append(.pair~new("02-03", "Devils")) |
|||
a~append(.pair~new("01-02", "Red Wings")) |
|||
a~append(.pair~new("03-04", "Lightning")) |
|||
a~append(.pair~new("04-05", "lockout")) |
|||
a~append(.pair~new("05-06", "Hurricanes")) |
|||
a~append(.pair~new("99-00", "Devils")) |
|||
a~append(.pair~new("07-08", "Red Wings")) |
|||
a~append(.pair~new("08-09", "Penguins")) |
|||
b = a~copy -- make a copy before sorting |
|||
b~sort |
|||
say "Sorted using direct comparison" |
|||
do pair over b |
|||
say pair |
|||
end |
|||
c = a~copy |
|||
-- this uses a custom comparator instead |
|||
c~sortWith(.paircomparator~new) |
|||
say |
|||
say "Sorted using a comparator (inverted)" |
|||
do pair over c |
|||
say pair |
|||
end |
|||
-- a name/value mapping class that directly support the sort comparisons |
|||
::class pair inherit comparable |
|||
::method init |
|||
expose name value |
|||
use strict arg name, value |
|||
::attribute name |
|||
::attribute value |
|||
::method string |
|||
expose name value |
|||
return name "=" value |
|||
-- the compareto method is a requirement brought in |
|||
-- by the |
|||
::method compareto |
|||
expose name |
|||
use strict arg other |
|||
return name~compareto(other~name) |
|||
-- a comparator that shows an alternate way of sorting |
|||
::class pairComparator subclass comparator |
|||
::method compare |
|||
use strict arg left, right |
|||
-- perform the comparison on the names |
|||
return -left~name~compareTo(right~name) |
|||
</syntaxhighlight> |
|||
Output: |
|||
<pre> |
|||
Sorted using direct comparison |
|||
00-01 = Avalanche |
|||
01-02 = Red Wings |
|||
02-03 = Devils |
|||
03-04 = Lightning |
|||
04-05 = lockout |
|||
05-06 = Hurricanes |
|||
06-07 = Ducks |
|||
07-08 = Red Wings |
|||
08-09 = Penguins |
|||
99-00 = Devils |
|||
Sorted using a comparator (inverted) |
|||
99-00 = Devils |
|||
08-09 = Penguins |
|||
07-08 = Red Wings |
|||
06-07 = Ducks |
|||
05-06 = Hurricanes |
|||
04-05 = lockout |
|||
03-04 = Lightning |
|||
02-03 = Devils |
|||
01-02 = Red Wings |
|||
00-01 = Avalanche |
|||
</pre> |
|||
=={{header|Oz}}== |
|||
<syntaxhighlight lang="oz">declare |
|||
People = [person(name:joe value:3) |
|||
person(name:bill value:4) |
|||
person(name:alice value:20) |
|||
person(name:harry value:3)] |
|||
SortedPeople = {Sort People |
|||
fun {$ P1 P2} |
|||
P1.name < P2.name |
|||
end |
|||
} |
|||
in |
|||
{ForAll SortedPeople Show}</syntaxhighlight> |
|||
=={{header|PARI/GP}}== |
|||
The flag "2" means that lexicographic sorting is to be used; the "1" means that the array is to be sorted using the first element of each constituent vector. |
|||
<syntaxhighlight lang="parigp">vecsort([["name", "value"],["name2", "value2"]], 1, 2)</syntaxhighlight> |
|||
=={{header|Pascal}}== |
|||
mergesort example sorts an array of record http://rosettacode.org/wiki/Sorting_algorithms/Merge_sort#improvement |
|||
=={{header|PascalABC.NET}}== |
|||
<syntaxhighlight lang="delphi"> |
|||
type |
|||
Pair = auto class |
|||
Name,Value: string; |
|||
end; |
|||
begin |
|||
var a: array of Pair := (new Pair('ZZZ','333'),new Pair('XXX','222'),new Pair('YYY','111')); |
|||
a.OrderBy(p -> p.Name).Println; |
|||
a.OrderBy(p -> p.Value).Println; |
|||
end. |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
(XXX,222) (YYY,111) (ZZZ,333) |
|||
(YYY,111) (XXX,222) (ZZZ,333) |
|||
</pre> |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
Sort by name using cmp to compare strings: |
Sort by name using cmp to compare strings: |
||
<syntaxhighlight lang="perl">@people = (['joe', 120], ['foo', 31], ['bar', 51]); |
|||
@people = sort { $a->[0] cmp $b->[0] } @people;</syntaxhighlight> |
|||
Sort by number using <=> to compare numbers: |
Sort by number using <=> to compare numbers: |
||
<syntaxhighlight lang="perl">@people = (['joe', 120], ['foo', 31], ['bar', 51]); |
|||
@people = sort { $a->[1] <=> $b->[1] } @people;</syntaxhighlight> |
|||
=={{header| |
=={{header|Phix}}== |
||
{{libheader|Phix/basics}} |
|||
The easy case describe in this task, the name is the first item of a tuple, simple sort just works: |
|||
The standard sort compares the first element, then 2nd, 3rd, etc. A custom_sort or sort_columns can be used to sort by other elements.<br> |
|||
Elements can be any mix of types, with atoms (ie ints/floats) deemed less than sequences/strings. |
|||
<!--<syntaxhighlight lang="phix">--> |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #008000;">"grass"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"green"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"snow"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"white"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"sky"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"blue"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">"cherry"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"red"</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1.2</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">3.4</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}}</span> |
|||
<span style="color: #0000FF;">?</span><span style="color: #7060A8;">sort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">compare_col2</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">return</span> <span style="color: #7060A8;">compare</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">],</span><span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #0000FF;">?</span><span style="color: #7060A8;">custom_sort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">compare_col2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #0000FF;">?</span><span style="color: #7060A8;">sort_columns</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">2</span><span style="color: #0000FF;">})</span> <span style="color: #000080;font-style:italic;">-- 0.8.0+, same result as above w/o needing an explicit comparison routine</span> |
|||
<!--</syntaxhighlight>--> |
|||
{{out}} |
|||
<pre> |
|||
{{0,1.2},{3.4,-1},{"cherry","red"},{"grass","green"},{"sky","blue"},{"snow","white"}} |
|||
{{3.4,-1},{0,1.2},{"sky","blue"},{"grass","green"},{"cherry","red"},{"snow","white"}} |
|||
{{3.4,-1},{0,1.2},{"sky","blue"},{"grass","green"},{"cherry","red"},{"snow","white"}} |
|||
</pre> |
|||
=={{header|Phixmonti}}== |
|||
people = [('joe', 120), ('foo', 31), ('bar', 51)] |
|||
<syntaxhighlight lang="phixmonti">include ..\Utilitys.pmt |
|||
people.sort() |
|||
def minverse |
|||
If the name is not the first one, you can use a cmp (for comparison) function: |
|||
reverse |
|||
enddef |
|||
getid minverse var f |
|||
people = [(120, 'joe'), (31, 'foo'), (51, 'bar')] |
|||
people.sort( lambda x, y: cmp(x[1], y[1]) ) |
|||
( ( "grass" "green" ) ( "snow" "white" ) ( "sky" "blue" ) ( "cherry" "red" ) ( 0 1.2 ) ( 3.4 -1 ) ) |
|||
But this is slow for large data sets. To make it much faster, use the [http://en.wikipedia.org/wiki/Schwartzian_transform Schwartzian_transform]: |
|||
dup |
|||
sort print nl |
|||
people = [(120, 'joe'), (31, 'foo'), (51, 'bar')] |
|||
tmp = [(person[1], person) for person in people] |
|||
tmp.sort() |
|||
people = [person for key, person in tmp] |
|||
/# sorted by second component #/ |
|||
Recent Python versions add a key argument to sort, which make this much cleaner: |
|||
f map sort f map print</syntaxhighlight> |
|||
=={{header|PicoLisp}}== |
|||
By default, the [http://software-lab.de/doc/refS.html#sort sort] function in |
|||
PicoLisp returns an ascending list (of any type) |
|||
<syntaxhighlight lang="picolisp">: (sort '(("def" 456) ("abc" 789) ("ghi" 123))) |
|||
-> (("abc" 789) ("def" 456) ("ghi" 123))</syntaxhighlight> |
|||
To sort by a certain sub-element, the function |
|||
[http://software-lab.de/doc/refB.html#by by] can be used. For example, to |
|||
sort by the first element |
|||
<syntaxhighlight lang="picolisp">: (by car sort '(("def" 456) ("abc" 789) ("ghi" 123))) |
|||
-> (("abc" 789) ("def" 456) ("ghi" 123))</syntaxhighlight> |
|||
or by the second element |
|||
<syntaxhighlight lang="picolisp">: (by cadr sort '(("def" 456) ("abc" 789) ("ghi" 123))) |
|||
-> (("ghi" 123) ("def" 456) ("abc" 789))</syntaxhighlight> |
|||
=={{header|PowerShell}}== |
|||
{{works with|PowerShell|4.0}} |
|||
<syntaxhighlight lang="powershell"> |
|||
$list = @{ |
|||
"def" = "one" |
|||
"abc" = "two" |
|||
"jkl" = "three" |
|||
"abcdef" = "four" |
|||
"ghi" = "five" |
|||
"ghijkl" = "six" |
|||
} |
|||
$list.GetEnumerator() | sort {-($PSItem.Name).length}, Name |
|||
</syntaxhighlight> |
|||
<b>Output:</b> |
|||
<pre> |
|||
Name Value |
|||
---- ----- |
|||
abcdef four |
|||
ghijkl six |
|||
abc two |
|||
def one |
|||
ghi five |
|||
jkl three |
|||
</pre> |
|||
=={{header|PureBasic}}== |
|||
PureBasic natively supports sorting of structured data with; |
|||
*SortStructuredArray() |
|||
*SortStructuredList() |
|||
The [http://www.purebasic.com/documentation/sort/index.html on-line documentations] gives a more complete picture. |
|||
'''Example''' |
|||
<syntaxhighlight lang="purebasic">Structure MyPair ; Define a structured data type |
|||
Name$ |
|||
Value.i |
|||
EndStructure |
|||
Dim People.MyPair(2) ; Allocate some elements |
|||
People(0)\Name$ = "John" ; Start filling them in |
|||
People(0)\Value = 100 |
|||
People(1)\Name$ = "Emma" |
|||
People(1)\Value = 200 |
|||
People(2)\Name$ = "Johnny" |
|||
People(2)\Value = 175 |
|||
If OpenConsole() |
|||
Define i |
|||
; Sort ascending by name |
|||
SortStructuredArray(People(), #PB_Sort_Ascending, OffsetOf(MyPair\Name$), #PB_Sort_String) |
|||
PrintN(#CRLF$+"Sorted ascending by name.") |
|||
For i=0 To 2 |
|||
PrintN(People(i)\Name$+" - Value: "+Str(People(i)\Value)) |
|||
Next |
|||
; Sort descending by value |
|||
SortStructuredArray(People(), #PB_Sort_Descending, OffsetOf(MyPair\Value), #PB_Sort_Integer) |
|||
PrintN(#CRLF$+"Sorted descending by value.") |
|||
For i=0 To 2 |
|||
PrintN(People(i)\Name$+" - Value: "+Str(People(i)\Value)) |
|||
Next |
|||
; Wait for user... |
|||
PrintN(#CRLF$+"Press ENTER to exit"):Input() |
|||
EndIf</syntaxhighlight> |
|||
'''Outputs |
|||
Sorted ascending by name. |
|||
Emma - Value: 200 |
|||
John - Value: 100 |
|||
Johnny - Value: 175 |
|||
Sorted descending by value. |
|||
people = [(120, 'joe'), (31, 'foo'), (51, 'bar')] |
|||
Emma - Value: 200 |
|||
people.sort(key=lambda x: x[0]) |
|||
Johnny - Value: 175 |
|||
John - Value: 100 |
|||
=={{header|Python}}== |
|||
The most Pythonic (and faster) version is using itemgetter: |
|||
Recent versions of Python provide the ''sorted()'' built-in that works on any iterable. |
|||
<syntaxhighlight lang="python">people = [('joe', 120), ('foo', 31), ('bar', 51)] |
|||
from operator import itemgetter |
|||
sorted(people)</syntaxhighlight> |
|||
people = [(120, 'joe'), (31, 'foo'), (51, 'bar')] |
|||
Which leaves <code>people</code> with the value: |
|||
people.sort(key=itemgetter(0)) |
|||
<syntaxhighlight lang="python">[('bar', 51), ('foo', 31), ('joe', 120)]</syntaxhighlight> |
|||
<br>The most Pythonic (and fastest) version is to use itemgetter together with the key parameter to <code>sort</code> resp. <code>sorted</code> to perform the [[wp:Decorate-sort-undecorate|Decorate-sort-undecorate]] pattern: |
|||
<syntaxhighlight lang="python">from operator import itemgetter |
|||
people = [(120, 'joe'), (31, 'foo'), (51, 'bar')] |
|||
people.sort(key=itemgetter(1))</syntaxhighlight> |
|||
Which leaves <code>people</code> with the value: |
|||
<syntaxhighlight lang="python">[(51, 'bar'), (31, 'foo'), (120, 'joe')]</syntaxhighlight> |
|||
=={{header|R}}== |
|||
In R, vectors can have names associated with any of its elements. The data is taken from the Common Lisp example. |
|||
<syntaxhighlight lang="r">sortbyname <- function(x, ...) x[order(names(x), ...)] |
|||
x <- c(texas=68.9, ohio=87.8, california=76.2, "new york"=88.2) |
|||
sortbyname(x)</syntaxhighlight> |
|||
california new york ohio texas |
|||
76.2 88.2 87.8 68.9 |
|||
<syntaxhighlight lang="r">sortbyname(x, decreasing=TRUE)</syntaxhighlight> |
|||
texas ohio new york california |
|||
68.9 87.8 88.2 76.2 |
|||
=={{header|Racket}}== |
|||
<syntaxhighlight lang="racket"> |
|||
#lang racket |
|||
(define data '([Joe 5531] [Adam 2341] [Bernie 122] [Walter 1234] [David 19])) |
|||
(sort data < #:key cadr) |
|||
;; --> '((David 19) (Bernie 122) (Walter 1234) (Adam 2341) (Joe 5531)) |
|||
;; Demonstrating a "key" that is not just a direct element |
|||
(sort data string<? #:key (compose1 symbol->string car)) |
|||
;; --> '((Adam 2341) (Bernie 122) (David 19) (Joe 5531) (Walter 1234)) |
|||
</syntaxhighlight> |
|||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
{{Works with|rakudo|2016.05}} |
|||
<syntaxhighlight lang="raku" line>my class Employee { |
|||
has Str $.name; |
|||
has Rat $.wage; |
|||
} |
|||
my $boss = Employee.new( name => "Frank Myers" , wage => 6755.85 ); |
|||
my $driver = Employee.new( name => "Aaron Fast" , wage => 2530.40 ); |
|||
my $worker = Employee.new( name => "John Dude" , wage => 2200.00 ); |
|||
my $salesman = Employee.new( name => "Frank Mileeater" , wage => 4590.12 ); |
|||
my @team = $boss, $driver, $worker, $salesman; |
|||
my @orderedByName = @team.sort( *.name )».name; |
|||
my @orderedByWage = @team.sort( *.wage )».name; |
|||
say "Team ordered by name (ascending order):"; |
|||
say @orderedByName.join(' '); |
|||
say "Team ordered by wage (ascending order):"; |
|||
say @orderedByWage.join(' ');</syntaxhighlight> |
|||
this produces the following output: |
|||
<pre>Team ordered by name (ascending order): |
|||
Aaron Fast Frank Mileeater Frank Myers John Dude |
|||
Team ordered by wage (ascending order): |
|||
John Dude Aaron Fast Frank Mileeater Frank Myers |
|||
</pre> |
|||
Note that when the sort receives a unary function, it automatically generates an appropriate comparison function based on the type of the data. |
|||
=={{header|REXX}}== |
|||
===General remarks=== |
|||
Both Regina and Classic ooRexx have standard no sorting facilities built-in. However, we have Patrick McPhee's library Regutil for Regina offering SysStemSort (sort 1 stem) and RegMultiStemSort (sort 1 key stem, syncing 1 to n data stems). And ooRexx has RexxUtil offering SysStemSort (sort 1 stem). Both utilities support only a string sort and require you to build a concatenated key (fixed columns for key values) in case of multiple sort arguments (as in this task). And, by the way, their parameters are not compatible.<br> |
|||
But we want our solutions in this category to run at least under both Regina and ooRexx. Thus a solution must be found for the limitations around stems, i.e. not be able to pass a stem to a procedure nor return one. |
|||
===Version 1=== |
|||
This version sorts the structure by color; as entered (built), the structure is ordered by value (percent). <br> |
|||
The name x. is used for the stem, with associated pairs x.1.color, x.2. color etc and x.1.value, x.2.value etc. Stem x. is exposed to all procedures needing it. |
|||
<syntaxhighlight lang="rexx">/*REXX program sorts an array of composite structures */ |
|||
/* (which has two classes of data). */ |
|||
x.=0 /*number elements in structure (so far)*/ |
|||
Call add 'tan' , 0 /*tan peanut M&M's are 0% of total*/ |
|||
Call add 'orange',10 /*orange " " " 10% " " */ |
|||
Call add 'yellow',20 /*yellow " " " 20% " " */ |
|||
Call add 'green' ,20 /*green " " " 20% " " */ |
|||
Call add 'red' ,20 /*red " " " 20% " " */ |
|||
Call add 'brown' ,30 /*brown " " " 30% " " */ |
|||
Call show 'before sort' |
|||
Say copies('¦', 70) |
|||
Call xSort |
|||
call show ' after sort' |
|||
Exit /*stick a fork in it, we're all done. */ |
|||
/*--------------------------------------------------------------------*/ |
|||
add: Procedure Expose x. |
|||
z=x.0+1 /* bump the number of structure entry */ |
|||
x.z.color=arg(1) |
|||
x.z.pc=arg(2) /* construct an entry of the structure */ |
|||
x.0=z |
|||
Return |
|||
/*--------------------------------------------------------------------*/ |
|||
show: Procedure Expose x. |
|||
Do i=1 To x.0 |
|||
/* display what name value. */ |
|||
Say right(arg(1),30) right(x.i.color,9) right(x.i.pc,4)'%' |
|||
End |
|||
Return |
|||
/*--------------------------------------------------------------------*/ |
|||
xsort: Procedure Expose x. |
|||
h=x.0 |
|||
Do While h>1 |
|||
h=h%2 |
|||
Do i=1 For x.0-h |
|||
j=i |
|||
k=h+i |
|||
Do While x.k.color<x.j.color |
|||
_=x.j.color /* swap elements. */ |
|||
x.j.color=x.k.color |
|||
x.k.color=_ |
|||
_=x.j.pc |
|||
x.j.pc=x.k.pc |
|||
x.k.pc=_ |
|||
If h>=j Then |
|||
Leave |
|||
j=j-h |
|||
k=k-h |
|||
End |
|||
End |
|||
End |
|||
Return</syntaxhighlight> |
|||
'''output''' when using the (internal) default inputs: |
|||
<pre> |
|||
before sort tan 0% |
|||
before sort orange 10% |
|||
before sort yellow 20% |
|||
before sort green 20% |
|||
before sort red 20% |
|||
before sort brown 30% |
|||
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ |
|||
after sort brown 30% |
|||
after sort green 20% |
|||
after sort orange 10% |
|||
after sort red 20% |
|||
after sort tan 0% |
|||
after sort yellow 20% |
|||
</pre> |
|||
===Realistic example=== |
|||
I asked ChatGPT (nice tool...): 'Give me a list of all US states, and per state the 3 cities with the highest population, in CSV format'. The result was neatly sorted, but for this example I shuffled the list. It shows as |
|||
<pre style="overflow: scroll; height: 50em"> |
|||
California,Los Angeles,3884307 |
|||
Utah,Salt Lake City,199927 |
|||
New Mexico,Las Cruces,111385 |
|||
California,San Diego,1423851 |
|||
California,San Jose,1021795 |
|||
Missouri,Saint Louis,302838 |
|||
New Mexico,Rio Rancho,101008 |
|||
Michigan,Grand Rapids,197416 |
|||
Nevada,Reno,260068 |
|||
Idaho,Nampa,100200 |
|||
Arizona,Mesa,508958 |
|||
Oregon,Eugene,176654 |
|||
Maine,Bangor,32178 |
|||
Texas,Houston,2325502 |
|||
Utah,Provo,116288 |
|||
Alaska,Juneau,31275 |
|||
Texas,Dallas,1335795 |
|||
Hawaii,Kailua,37713 |
|||
Florida,Tampa,392890 |
|||
Florida,Miami,478251 |
|||
Idaho,Boise,236310 |
|||
Oregon,Salem,168916 |
|||
Hawaii,Hilo,45784 |
|||
Ohio,Columbus,905748 |
|||
Iowa,Davenport,102320 |
|||
Idaho,Meridian,117322 |
|||
Alabama,Mobile,195111 |
|||
Maine,Lewiston,36277 |
|||
Ohio,Cleveland,372624 |
|||
Delaware,Dover,38202 |
|||
Kansas,Wichita,391731 |
|||
Oklahoma,Tulsa,391906 |
|||
Nebraska,Omaha,486051 |
|||
Arizona,Tucson,548073 |
|||
Wyoming,Casper,58500 |
|||
Maine,Portland,67506 |
|||
South Carolina,Charleston,150227 |
|||
North Carolina,Charlotte,874579 |
|||
South Carolina,Columbia,137318 |
|||
North Carolina,Greensboro,306614 |
|||
South Carolina,North Charleston,118974 |
|||
North Carolina,Raleigh,474069 |
|||
Massachusetts,Boston,645966 |
|||
Vermont,South Burlington,19480 |
|||
West Virginia,Charleston,48387 |
|||
Kansas,Kansas City,152960 |
|||
New Hampshire,Concord,42629 |
|||
Montana,Great Falls,59488 |
|||
West Virginia,Huntington,45531 |
|||
New Hampshire,Manchester,115644 |
|||
New Hampshire,Nashua,88341 |
|||
Louisiana,New Orleans,384320 |
|||
West Virginia,Parkersburg,30701 |
|||
Arkansas,Fort Smith,87674 |
|||
Massachusetts,Springfield,153606 |
|||
Massachusetts,Worcester,185885 |
|||
Illinois,Aurora,197757 |
|||
Georgia,Augusta,202679 |
|||
Colorado,Aurora,361710 |
|||
Georgia,Atlanta,498715 |
|||
Colorado,Colorado Springs,457568 |
|||
Connecticut,Stamford,129775 |
|||
South Dakota,Rapid City,74388 |
|||
Indiana,Indianapolis,855164 |
|||
North Dakota,Fargo,124662 |
|||
New Jersey,Newark,281054 |
|||
Rhode Island,Warwick,81481 |
|||
Nevada,Las Vegas,641676 |
|||
Wisconsin,Milwaukee,592025 |
|||
Indiana,Fort Wayne,264488 |
|||
South Dakota,Aberdeen,27653 |
|||
Mississippi,Jackson,172638 |
|||
Kansas,Overland Park,190886 |
|||
Vermont,Rutland,15942 |
|||
Oregon,Portland,632309 |
|||
Arkansas,Little Rock,202591 |
|||
Wyoming,Laramie,32311 |
|||
Minnesota,Minneapolis,429606 |
|||
Maryland,Gaithersburg,67404 |
|||
New Jersey,Paterson,146199 |
|||
Minnesota,Rochester,223873 |
|||
Utah,West Valley City,136574 |
|||
Alaska,Anchorage,291538 |
|||
Missouri,Springfield,165794 |
|||
Alabama,Birmingham,200733 |
|||
Illinois,Chicago,2716000 |
|||
Montana,Billings,109577 |
|||
Kentucky,Lexington,323780 |
|||
Vermont,Burlington,42304 |
|||
Pennsylvania,Philadelphia,1567442 |
|||
Tennessee,Memphis,660388 |
|||
Ohio,Cincinnati,298165 |
|||
Connecticut,Bridgeport,144399 |
|||
Iowa,Cedar Rapids,132228 |
|||
Indiana,Evansville,119943 |
|||
South Dakota,Sioux Falls,186502 |
|||
North Dakota,Bismarck,74151 |
|||
Michigan,Detroit,672662 |
|||
Pennsylvania,Pittsburgh,305704 |
|||
Delaware,Newark,34544 |
|||
Washington,Spokane,230707 |
|||
Alaska,Fairbanks,31516 |
|||
Montana,Missoula,68220 |
|||
Mississippi,Gulfport,71375 |
|||
Virginia,Norfolk,244835 |
|||
Pennsylvania,Allentown,118577 |
|||
Nebraska,Lincoln,280849 |
|||
New York,Buffalo,256480 |
|||
Alabama,Montgomery,199518 |
|||
Maryland,Baltimore,622104 |
|||
Wisconsin,Green Bay,107395 |
|||
Louisiana,Baton Rouge,227715 |
|||
Oklahoma,Norman,124880 |
|||
Michigan,Warren,134056 |
|||
Wyoming,Cheyenne,64235 |
|||
Kentucky,Bowling Green,67226 |
|||
Delaware,Wilmington,70973 |
|||
Virginia,Virginia Beach,450189 |
|||
Texas,San Antonio,1532233 |
|||
Florida,Jacksonville,949611 |
|||
Oklahoma,Oklahoma City,649021 |
|||
Washington,Tacoma,213418 |
|||
Nevada,Henderson,310390 |
|||
New York,New York,8537673 |
|||
Virginia,Chesapeake,247036 |
|||
Colorado,Denver,716492 |
|||
North Dakota,Grand Forks,55231 |
|||
Rhode Island,Cranston,80566 |
|||
Maryland,Frederick,71726 |
|||
Rhode Island,Providence,179207 |
|||
Missouri,Kansas City,508090 |
|||
Iowa,Des Moines,214237 |
|||
New Jersey,Jersey City,280579 |
|||
Wisconsin,Madison,258054 |
|||
New York,Rochester,208046 |
|||
Minnesota,Saint Paul,308096 |
|||
Arkansas,Fayetteville,74880 |
|||
Washington,Seattle,787995 |
|||
Hawaii,Honolulu,337256 |
|||
New Mexico,Albuquerque,559277 |
|||
Georgia,Columbus,206922 |
|||
Mississippi,Southaven,55200 |
|||
Louisiana,Shreveport,194920 |
|||
Illinois,Naperville,147122 |
|||
Tennessee,Knoxville,190740 |
|||
Kentucky,Louisville,621349 |
|||
Tennessee,Nashville,634464 |
|||
Nebraska,Bellevue,272117 |
|||
Connecticut,New Haven,130322 |
|||
Arizona,Phoenix,1680992 |
|||
</pre> |
|||
A nice table to play with: duplicates in the first entry and numeric values in the last entry. I stored it in States.txt, and will use it in subsequential examples.<br> |
|||
Now, let's use a 'database' approach, just like in the entry [[Sort_an_array_of_composite_structures#SQL]]<br> |
|||
Above data forms a table, say '''states''', having three columns '''state (char)''', '''city (char)''' and '''pop (int)'''. So let's use a stem with head 'states.' and tails 'state.x', 'city.x' and 'pop.x', x = row number. Exposing 'states.' to each procedures serves as providing a table to the procedure. And let states.0 hold the number of rows. This naming convention closely mimics the fully qualified names for tables and columns in SQL, and shows clearly the relation between the tails as belonging to the head 'states.'.<br> |
|||
By the way, this way of naming and storing is essentially the same as in Version 1, nothing new here.<br> |
|||
===Libraries=== |
|||
REXX does not have an 'include' facility nor 'arbitrary precision' mathematical functions out of the |
|||
box. In previous REXX entries it was custom the have all needed routines and procedures copied into |
|||
the program. Newer entries redirect to<br> |
|||
[[Mathematics.rex|Libraries]] and<br> |
|||
[[Compiler/Simple file inclusion pre processor#rexx|Pre processor and Include clause]].<br> |
|||
At the end of each entry you'll find several 'include' clauses, showing the libraries that the program |
|||
needs (cf '#include', 'import', 'uses' or '::requires').<br> |
|||
The use of this tool is highly recommended. But you may always copy the source code into your program |
|||
and do the text changes yourself, i.e. change all '[label]' to 'some_name' etc. |
|||
===Versions 2 and 3=== |
|||
Now, using the data structure |
|||
* states. (table) |
|||
* states.0 = n (number of rows) |
|||
* states.state.x (column state) |
|||
* states.city.x (column city) |
|||
* states.pop.x (column population) |
|||
we arrive at following program and procedures.<br> |
|||
Program, creating a table and invoking several sorts on different columns, using two types of (quick)sorting procedure. |
|||
<syntaxhighlight lang="rexx" style="overflow: scroll; height: 30em"> |
|||
Main: |
|||
call Create |
|||
call Show 'Not ordered' |
|||
call SortStateCity |
|||
call Show 'By state and city' |
|||
call SortPopCityN |
|||
call Show 'By pop (numeric desc) and city' |
|||
table = 'states.'; keys = 'pop. state.'; data = 'city.' |
|||
call SortPopCityS table,keys,data |
|||
call Show 'By pop (string) and city' |
|||
table = 'states.'; keys = 'city. state.'; data = 'pop.' |
|||
call SortCityState table,keys,data |
|||
call Show 'By city and state' |
|||
return |
|||
Create: |
|||
states = 'States.txt' |
|||
call Stream states,'c','open read' |
|||
states. = ''; n = 0 |
|||
do while lines(states) > 0 |
|||
record = linein(states) |
|||
parse var record rstate','rcity','rpop |
|||
n = n+1; states.state.n = rstate; states.city.n = rcity; states.pop.n = rpop |
|||
end |
|||
call Stream states,'c','close' |
|||
states.0 = n |
|||
return |
|||
Show: |
|||
procedure expose states. |
|||
arg header |
|||
say center(header,53) |
|||
say right('row',3) left('state',20) left('city',20) right('pop',7) |
|||
do n = 1 to states.0 |
|||
say right(n,3) left(states.state.n,20) left(states.city.n,20) right(states.pop.n,7) |
|||
end |
|||
say |
|||
return |
|||
include Quicksort21 [label]=SortStateCity [table]=states. [key1]=state. [key2]=city. [data1]=pop. |
|||
include Quicksort21 [label]=SortPopCityN [table]=states. [key1]=pop. [key2]=city. [data1]=state. [lt]=> [gt]=< |
|||
include Quicksort [label]=SortCityState |
|||
include Quicksort [label]=SortPopCityS [lt]=<< [gt]=>> |
|||
</syntaxhighlight> |
|||
Quicksort, optimized for exactly 2 key columns and 1 data column. |
|||
<syntaxhighlight lang="rexx" style="overflow: scroll; height: 30em"> |
|||
default [label]=Quicksort21 [table]=table. [key1]=key1. [key2]=key2. [data1]=data1. [lt]=< [eq]== [gt]=> |
|||
-- Sorting procedure - Build 20240806 |
|||
-- (C) Paul van den Eertwegh 2024 |
|||
[label]: |
|||
-- Sort a stem on 2 key columns, syncing 1 data column |
|||
procedure expose [table] |
|||
-- Sort |
|||
n = [table]0; s = 1; sl.1 = 1; sr.1 = n |
|||
do until s = 0 |
|||
l = sl.s; r = sr.s; s = s-1 |
|||
do until l >= r |
|||
-- Up to 19 rows selection sort is faster |
|||
if r-l < 20 then do |
|||
do i = l+1 to r |
|||
a = [table][key1]i |
|||
b = [table][key2]i |
|||
c = [table][data1]i |
|||
do j = i-1 by -1 to l |
|||
if [table][key1]j [lt] a then |
|||
leave |
|||
if [table][key1]j [eq] a then |
|||
if [table][key2]j [lt]= b then |
|||
leave |
|||
k = j+1 |
|||
[table][key1]k = [table][key1]j |
|||
[table][key2]k = [table][key2]j |
|||
[table][data1]k = [table][data1]j |
|||
end |
|||
k = j+1 |
|||
[table][key1]k = a |
|||
[table][key2]k = b |
|||
[table][data1]k = c |
|||
end |
|||
if s = 0 then |
|||
leave |
|||
l = sl.s; r = sr.s; s = s-1 |
|||
end |
|||
else do |
|||
-- Find optimized pivot |
|||
m = (l+r)%2 |
|||
if [table][key1]l [gt] [table][key1]m then do |
|||
t = [table][key1]l; [table][key1]l = [table][key1]m; [table][key1]m = t |
|||
t = [table][key2]l; [table][key2]l = [table][key2]m; [table][key2]m = t |
|||
t = [table][data1]l; [table][data1]l = [table][data1]m; [table][data1]m = t |
|||
end |
|||
else do |
|||
if [table][key1]l [eq] [table][key1]m then do |
|||
if [table][key2]l [gt] [table][key2]m then do |
|||
t = [table][key2]l; [table][key2]l = [table][key2]m; [table][key2]m = t |
|||
t = [table][data1]l; [table][data1]l = [table][data1]m; [table][data1]m = t |
|||
end |
|||
end |
|||
end |
|||
if [table][key1]l [gt] [table][key1]r then do |
|||
t = [table][key1]l; [table][key1]l = [table][key1]r; [table][key1]r = t |
|||
t = [table][key2]l; [table][key2]l = [table][key2]r; [table][key2]r = t |
|||
t = [table][data1]l; [table][data1]l = [table][data1]r; [table][data1]r = t |
|||
end |
|||
else do |
|||
if [table][key1]l [eq] [table][key1]r then do |
|||
if [table][key2]l [gt] [table][key2]r then do |
|||
t = [table][key2]l; [table][key2]l = [table][key2]r; [table][key2]r = t |
|||
t = [table][data1]l; [table][data1]l = [table][data1]r; [table][data1]r = t |
|||
end |
|||
end |
|||
end |
|||
if [table][key1]m [gt] [table][key1]r then do |
|||
t = [table][key1]m; [table][key1]m = [table][key1]r; [table][key1]r = t |
|||
t = [table][key2]m; [table][key2]m = [table][key2]r; [table][key2]r = t |
|||
t = [table][data1]m; [table][data1]m = [table][data1]r; [table][data1]r = t |
|||
end |
|||
else do |
|||
if [table][key1]m [eq] [table][key1]r then do |
|||
if [table][key2]m [gt] [table][key2]r then do |
|||
t = [table][key2]m; [table][key2]m = [table][key2]r; [table][key2]r = t |
|||
t = [table][data1]m; [table][data1]m = [table][data1]r; [table][data1]r = t |
|||
end |
|||
end |
|||
end |
|||
-- Rearrange rows in partition |
|||
i = l; j = r |
|||
a = [table][key1]m |
|||
b = [table][key2]m |
|||
do until i > j |
|||
do i = i |
|||
if [table][key1]i [gt] a then |
|||
leave |
|||
if [table][key1]i [eq] a then |
|||
if [table][key2]i [gt]= b then |
|||
leave |
|||
end |
|||
do j = j by -1 |
|||
if [table][key1]j [lt] a then |
|||
leave |
|||
if [table][key1]j [eq] a then |
|||
if [table][key2]j [lt]= b then |
|||
leave |
|||
end |
|||
if i <= j then do |
|||
t = [table][key1]i; [table][key1]i = [table][key1]j; [table][key1]j = t |
|||
t = [table][key2]i; [table][key2]i = [table][key2]j; [table][key2]j = t |
|||
t = [table][data1]i; [table][data1]i = [table][data1]j; [table][data1]j = t |
|||
i = i+1; j = j-1 |
|||
end |
|||
end |
|||
-- Next partition |
|||
if j-l < r-i then do |
|||
if i < r then do |
|||
s = s+1; sl.s = i; sr.s = r |
|||
end |
|||
r = j |
|||
end |
|||
else do |
|||
if l < j then do |
|||
s = s+1; sl.s = l; sr.s = j |
|||
end |
|||
l = i |
|||
end |
|||
end |
|||
end |
|||
end |
|||
return |
|||
</syntaxhighlight> |
|||
Quicksort, able to sort a table on any number of key columns, syncing any number of data columns.<br> |
|||
Ugh... Nasty code with all those calls to Value(), but it works. Check the documentation on the Value() function if you are not familiar with it. |
|||
<syntaxhighlight lang="rexx" style="overflow: scroll; height: 30em"> |
|||
default [label]=Quicksort [lt]=< [eq]== [gt]=> |
|||
/* Sorting procedure - Build 20240805 */ |
|||
/* (C) Paul van den Eertwegh 2024 */ |
|||
[label]: |
|||
/* Sort on 1 or more key stems, syncing 0 or more data stems */ |
|||
procedure expose (table) |
|||
arg table,keys,data |
|||
/* Collect keys */ |
|||
kn = words(keys) |
|||
do x = 1 to kn |
|||
key.x = word(keys,x) |
|||
end |
|||
/* Collect data */ |
|||
dn = words(data) |
|||
do x = 1 to dn |
|||
data.x = word(data,x) |
|||
end |
|||
/* Sort */ |
|||
n = value(table||0); s = 1; sl.1 = 1; sr.1 = n |
|||
do until s = 0 |
|||
l = sl.s; r = sr.s; s = s-1 |
|||
do until l >= r |
|||
/* Up to 19 rows selection sort is faster */ |
|||
if r-l < 20 then do |
|||
do i = l+1 to r |
|||
do x = 1 to kn |
|||
k.x = value(table||key.x||i) |
|||
end |
|||
do x = 1 to dn |
|||
d.x = value(table||data.x||i) |
|||
end |
|||
do j=i-1 to l by -1 |
|||
do x = 1 to kn |
|||
a = value(table||key.x||j) |
|||
if a [gt] k.x then |
|||
leave x |
|||
if a [eq] k.x then |
|||
if x < kn then |
|||
iterate x |
|||
leave j |
|||
end |
|||
k = j+1 |
|||
do x = 1 to kn |
|||
t = value(table||key.x||j) |
|||
call value table||key.x||k,t |
|||
end |
|||
do x = 1 to dn |
|||
t = value(table||data.x||j) |
|||
call value table||data.x||k,t |
|||
end |
|||
end |
|||
k = j+1 |
|||
do x = 1 to kn |
|||
call value table||key.x||k,k.x |
|||
end |
|||
do x = 1 to dn |
|||
call value table||data.x||k,d.x |
|||
end |
|||
end |
|||
if s = 0 then |
|||
leave |
|||
l = sl.s; r = sr.s; s = s-1 |
|||
end |
|||
else do |
|||
/* Find optimized pivot */ |
|||
m = (l+r)%2 |
|||
do x = 1 to kn |
|||
a = value(table||key.x||l); b = value(table||key.x||m) |
|||
if a [gt] b then do |
|||
do y = 1 to kn |
|||
t = value(table||key.y||l); u = value(table||key.y||m) |
|||
call value table||key.y||l,u; call value table||key.y||m,t |
|||
end |
|||
do y = 1 to dn |
|||
t = value(table||data.y||l); u = value(table||data.y||m) |
|||
call value table||data.y||l,u; call value table||data.y||m,t |
|||
end |
|||
leave |
|||
end |
|||
if a [lt] b then |
|||
leave |
|||
end |
|||
do x = 1 to kn |
|||
a = value(table||key.x||l); b = value(table||key.x||r) |
|||
if a [gt] b then do |
|||
do y = 1 to kn |
|||
t = value(table||key.y||l); u = value(table||key.y||r) |
|||
call value table||key.y||l,u; call value table||key.y||r,t |
|||
end |
|||
do y = 1 to dn |
|||
t = value(table||data.y||l); u = value(table||data.y||r) |
|||
call value table||data.y||l,u; call value table||data.y||r,t |
|||
end |
|||
leave |
|||
end |
|||
if a [lt] b then |
|||
leave |
|||
end |
|||
do x = 1 to kn |
|||
a = value(table||key.x||m); b = value(table||key.x||r) |
|||
if a [gt] b then do |
|||
do y = 1 to kn |
|||
t = value(table||key.y||m); u = value(table||key.y||r) |
|||
call value table||key.y||m,u; call value table||key.y||r,t |
|||
end |
|||
do y = 1 to dn |
|||
t = value(table||data.y||m); u = value(table||data.y||r) |
|||
call value table||data.y||m,u; call value table||data.y||r,t |
|||
end |
|||
leave |
|||
end |
|||
if a [lt] b then |
|||
leave |
|||
end |
|||
/* Rearrange rows in partition */ |
|||
i = l; j = r |
|||
do x = 1 to kn |
|||
p.x = value(table||key.x||m) |
|||
end |
|||
do until i > j |
|||
do i = i |
|||
do x = 1 to kn |
|||
a = value(table||key.x||i) |
|||
if a [lt] p.x then |
|||
leave x |
|||
if a [eq] p.x then |
|||
if x < kn then |
|||
iterate x |
|||
leave i |
|||
end |
|||
end |
|||
do j = j by -1 |
|||
do x = 1 to kn |
|||
a = value(table||key.x||j) |
|||
if a [gt] p.x then |
|||
leave x |
|||
if a [eq] p.x then |
|||
if x < kn then |
|||
iterate x |
|||
leave j |
|||
end |
|||
end |
|||
if i <= j then do |
|||
do x = 1 to kn |
|||
t = value(table||key.x||i); u = value(table||key.x||j) |
|||
call value table||key.x||i,u; call value table||key.x||j,t |
|||
end |
|||
do x = 1 to dn |
|||
t = value(table||data.x||i); u = value(table||data.x||j) |
|||
call value table||data.x||i,u; call value table||data.x||j,t |
|||
end |
|||
i = i+1; j = j-1 |
|||
end |
|||
end |
|||
/* Next partition */ |
|||
if j-l < r-i then do |
|||
if i < r then do |
|||
s = s+1; sl.s = i; sr.s = r |
|||
end |
|||
r = j |
|||
end |
|||
else do |
|||
if l < j then do |
|||
s = s+1; sl.s = l; sr.s = j |
|||
end |
|||
l = i |
|||
end |
|||
end |
|||
end |
|||
end |
|||
return |
|||
</syntaxhighlight> |
|||
You may have noticed the replaceable texts [lt], [eq] and [gt]. These are present in the procedures at strategic points and allows you to control the sort: ascending ([lt]=< and [gt]=>) vs descending ([lt]=> and [gt]=<) and numeric (use < = >) or string (use << == >>). See the rexx documentation about strict comparisons. The include clauses in the first program provide examples.<br> |
|||
Running the program yields following output. For the sorted entries only the first 10 rows are shown. |
|||
{{out|Output}} |
|||
<pre style="overflow: scroll; height: 30em"> |
|||
NOT ORDERED |
|||
row state city pop |
|||
1 California Los Angeles 3884307 |
|||
2 Utah Salt Lake City 199927 |
|||
3 New Mexico Las Cruces 111385 |
|||
4 California San Diego 1423851 |
|||
5 California San Jose 1021795 |
|||
6 Missouri Saint Louis 302838 |
|||
7 New Mexico Rio Rancho 101008 |
|||
8 Michigan Grand Rapids 197416 |
|||
9 Nevada Reno 260068 |
|||
10 Idaho Nampa 100200 |
|||
11 Arizona Mesa 508958 |
|||
12 Oregon Eugene 176654 |
|||
13 Maine Bangor 32178 |
|||
14 Texas Houston 2325502 |
|||
15 Utah Provo 116288 |
|||
16 Alaska Juneau 31275 |
|||
17 Texas Dallas 1335795 |
|||
18 Hawaii Kailua 37713 |
|||
19 Florida Tampa 392890 |
|||
20 Florida Miami 478251 |
|||
21 Idaho Boise 236310 |
|||
22 Oregon Salem 168916 |
|||
23 Hawaii Hilo 45784 |
|||
24 Ohio Columbus 905748 |
|||
25 Iowa Davenport 102320 |
|||
26 Idaho Meridian 117322 |
|||
27 Alabama Mobile 195111 |
|||
28 Maine Lewiston 36277 |
|||
29 Ohio Cleveland 372624 |
|||
30 Delaware Dover 38202 |
|||
31 Kansas Wichita 391731 |
|||
32 Oklahoma Tulsa 391906 |
|||
33 Nebraska Omaha 486051 |
|||
34 Arizona Tucson 548073 |
|||
35 Wyoming Casper 58500 |
|||
36 Maine Portland 67506 |
|||
37 South Carolina Charleston 150227 |
|||
38 North Carolina Charlotte 874579 |
|||
39 South Carolina Columbia 137318 |
|||
40 North Carolina Greensboro 306614 |
|||
41 South Carolina North Charleston 118974 |
|||
42 North Carolina Raleigh 474069 |
|||
43 Massachusetts Boston 645966 |
|||
44 Vermont South Burlington 19480 |
|||
45 West Virginia Charleston 48387 |
|||
46 Kansas Kansas City 152960 |
|||
47 New Hampshire Concord 42629 |
|||
48 Montana Great Falls 59488 |
|||
49 West Virginia Huntington 45531 |
|||
50 New Hampshire Manchester 115644 |
|||
51 New Hampshire Nashua 88341 |
|||
52 Louisiana New Orleans 384320 |
|||
53 West Virginia Parkersburg 30701 |
|||
54 Arkansas Fort Smith 87674 |
|||
55 Massachusetts Springfield 153606 |
|||
56 Massachusetts Worcester 185885 |
|||
57 Illinois Aurora 197757 |
|||
58 Georgia Augusta 202679 |
|||
59 Colorado Aurora 361710 |
|||
60 Georgia Atlanta 498715 |
|||
61 Colorado Colorado Springs 457568 |
|||
62 Connecticut Stamford 129775 |
|||
63 South Dakota Rapid City 74388 |
|||
64 Indiana Indianapolis 855164 |
|||
65 North Dakota Fargo 124662 |
|||
66 New Jersey Newark 281054 |
|||
67 Rhode Island Warwick 81481 |
|||
68 Nevada Las Vegas 641676 |
|||
69 Wisconsin Milwaukee 592025 |
|||
70 Indiana Fort Wayne 264488 |
|||
71 South Dakota Aberdeen 27653 |
|||
72 Mississippi Jackson 172638 |
|||
73 Kansas Overland Park 190886 |
|||
74 Vermont Rutland 15942 |
|||
75 Oregon Portland 632309 |
|||
76 Arkansas Little Rock 202591 |
|||
77 Wyoming Laramie 32311 |
|||
78 Minnesota Minneapolis 429606 |
|||
79 Maryland Gaithersburg 67404 |
|||
80 New Jersey Paterson 146199 |
|||
81 Minnesota Rochester 223873 |
|||
82 Utah West Valley City 136574 |
|||
83 Alaska Anchorage 291538 |
|||
84 Missouri Springfield 165794 |
|||
85 Alabama Birmingham 200733 |
|||
86 Illinois Chicago 2716000 |
|||
87 Montana Billings 109577 |
|||
88 Kentucky Lexington 323780 |
|||
89 Vermont Burlington 42304 |
|||
90 Pennsylvania Philadelphia 1567442 |
|||
91 Tennessee Memphis 660388 |
|||
92 Ohio Cincinnati 298165 |
|||
93 Connecticut Bridgeport 144399 |
|||
94 Iowa Cedar Rapids 132228 |
|||
95 Indiana Evansville 119943 |
|||
96 South Dakota Sioux Falls 186502 |
|||
97 North Dakota Bismarck 74151 |
|||
98 Michigan Detroit 672662 |
|||
99 Pennsylvania Pittsburgh 305704 |
|||
100 Delaware Newark 34544 |
|||
101 Washington Spokane 230707 |
|||
102 Alaska Fairbanks 31516 |
|||
103 Montana Missoula 68220 |
|||
104 Mississippi Gulfport 71375 |
|||
105 Virginia Norfolk 244835 |
|||
106 Pennsylvania Allentown 118577 |
|||
107 Nebraska Lincoln 280849 |
|||
108 New York Buffalo 256480 |
|||
109 Alabama Montgomery 199518 |
|||
110 Maryland Baltimore 622104 |
|||
111 Wisconsin Green Bay 107395 |
|||
112 Louisiana Baton Rouge 227715 |
|||
113 Oklahoma Norman 124880 |
|||
114 Michigan Warren 134056 |
|||
115 Wyoming Cheyenne 64235 |
|||
116 Kentucky Bowling Green 67226 |
|||
117 Delaware Wilmington 70973 |
|||
118 Virginia Virginia Beach 450189 |
|||
119 Texas San Antonio 1532233 |
|||
120 Florida Jacksonville 949611 |
|||
121 Oklahoma Oklahoma City 649021 |
|||
122 Washington Tacoma 213418 |
|||
123 Nevada Henderson 310390 |
|||
124 New York New York 8537673 |
|||
125 Virginia Chesapeake 247036 |
|||
126 Colorado Denver 716492 |
|||
127 North Dakota Grand Forks 55231 |
|||
128 Rhode Island Cranston 80566 |
|||
129 Maryland Frederick 71726 |
|||
130 Rhode Island Providence 179207 |
|||
131 Missouri Kansas City 508090 |
|||
132 Iowa Des Moines 214237 |
|||
133 New Jersey Jersey City 280579 |
|||
134 Wisconsin Madison 258054 |
|||
135 New York Rochester 208046 |
|||
136 Minnesota Saint Paul 308096 |
|||
137 Arkansas Fayetteville 74880 |
|||
138 Washington Seattle 787995 |
|||
139 Hawaii Honolulu 337256 |
|||
140 New Mexico Albuquerque 559277 |
|||
141 Georgia Columbus 206922 |
|||
142 Mississippi Southaven 55200 |
|||
143 Louisiana Shreveport 194920 |
|||
144 Illinois Naperville 147122 |
|||
145 Tennessee Knoxville 190740 |
|||
146 Kentucky Louisville 621349 |
|||
147 Tennessee Nashville 634464 |
|||
148 Nebraska Bellevue 272117 |
|||
149 Connecticut New Haven 130322 |
|||
150 Arizona Phoenix 1680992 |
|||
</pre> |
|||
<pre> |
|||
BY STATE AND CITY |
|||
row state city pop |
|||
1 Alabama Birmingham 200733 |
|||
2 Alabama Mobile 195111 |
|||
3 Alabama Montgomery 199518 |
|||
4 Alaska Anchorage 291538 |
|||
5 Alaska Fairbanks 31516 |
|||
6 Alaska Juneau 31275 |
|||
7 Arizona Mesa 508958 |
|||
8 Arizona Phoenix 1680992 |
|||
9 Arizona Tucson 548073 |
|||
10 Arkansas Fayetteville 74880 |
|||
... |
|||
</pre> |
|||
<pre> |
|||
BY POP (NUMERIC DESC) AND CITY |
|||
row state city pop |
|||
1 New York New York 8537673 |
|||
2 California Los Angeles 3884307 |
|||
3 Illinois Chicago 2716000 |
|||
4 Texas Houston 2325502 |
|||
5 Arizona Phoenix 1680992 |
|||
6 Pennsylvania Philadelphia 1567442 |
|||
7 Texas San Antonio 1532233 |
|||
8 California San Diego 1423851 |
|||
9 Texas Dallas 1335795 |
|||
10 California San Jose 1021795 |
|||
... |
|||
</pre> |
|||
<pre> |
|||
BY POP (STRING) AND CITY |
|||
row state city pop |
|||
1 Idaho Nampa 100200 |
|||
2 New Mexico Rio Rancho 101008 |
|||
3 California San Jose 1021795 |
|||
4 Iowa Davenport 102320 |
|||
5 Wisconsin Green Bay 107395 |
|||
6 Montana Billings 109577 |
|||
7 New Mexico Las Cruces 111385 |
|||
8 New Hampshire Manchester 115644 |
|||
9 Utah Provo 116288 |
|||
10 Idaho Meridian 117322 |
|||
... |
|||
</pre> |
|||
<pre> |
|||
BY CITY AND STATE |
|||
row state city pop |
|||
1 South Dakota Aberdeen 27653 |
|||
2 New Mexico Albuquerque 559277 |
|||
3 Pennsylvania Allentown 118577 |
|||
4 Alaska Anchorage 291538 |
|||
5 Georgia Atlanta 498715 |
|||
6 Georgia Augusta 202679 |
|||
7 Colorado Aurora 361710 |
|||
8 Illinois Aurora 197757 |
|||
9 Maryland Baltimore 622104 |
|||
10 Maine Bangor 32178 |
|||
... |
|||
</pre> |
|||
What's the performance of these sorts? I ran this example on some bigger tables, also with 2 keys and 1 data.<br> |
|||
A you might have guessed, the customized Quicksort21 is much faster than the general one. Indication of timings in seconds. |
|||
{| class="wikitable" |
|||
|+ Timing indication custom vs general Quicksort |
|||
|- |
|||
! Rows !! Regina cust !! Regina gen !! ooRexx cust !! ooRexx gen |
|||
|- |
|||
| 1k || 0.01 || 0.02 || 0.01 || 0.03 |
|||
|- |
|||
| 10k || 0.11 || 0.28 || 0.18 || 0.70 |
|||
|- |
|||
| 100k || 1.5 || 3.8 || 2.3 || 11.7 |
|||
|- |
|||
| 1m || 18 || 120 || 30 || 120 |
|||
|} |
|||
=={{header|Ring}}== |
|||
<syntaxhighlight lang="ring"> |
|||
aList= sort([:Eight = 8, :Two = 2, :Five = 5, :Nine = 9, :One = 1, |
|||
:Three = 3, :Six = 6, :Seven = 7, :Four = 4, :Ten = 10] , 2) |
|||
for item in aList |
|||
? item[1] + space(10-len(item[1])) + item[2] |
|||
next |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
one 1 |
|||
two 2 |
|||
three 3 |
|||
four 4 |
|||
five 5 |
|||
six 6 |
|||
seven 7 |
|||
eight 8 |
|||
nine 9 |
|||
ten 10 |
|||
</pre> |
|||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
Person = Struct.new(:name,:value) |
|||
<syntaxhighlight lang="ruby">Person = Struct.new(:name,:value) do |
|||
list = [Person.new("Joe",3), |
|||
def to_s; "name:#{name}, value:#{value}" end |
|||
Person.new("Bill",4), |
|||
end |
|||
Person.new("Alice",20), |
|||
Person.new("Harry",3)] |
|||
list = [Person.new("Joe",3), |
|||
list.sort_by{|x|x.name} |
|||
Person.new("Bill",4), |
|||
Person.new("Alice",20), |
|||
Person.new("Harry",3)] |
|||
puts list.sort_by{|x|x.name} |
|||
puts |
|||
puts list.sort_by(&:value)</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
name:Alice, value:20 |
|||
name:Bill, value:4 |
|||
name:Harry, value:3 |
|||
name:Joe, value:3 |
|||
name:Joe, value:3 |
|||
name:Harry, value:3 |
|||
name:Bill, value:4 |
|||
name:Alice, value:20 |
|||
</pre> |
|||
=={{header|Run BASIC}}== |
|||
<syntaxhighlight lang="runbasic">sqliteconnect #mem, ":memory:" ' create in memory db |
|||
mem$ = "CREATE TABLE people(num integer, name text,city text)" |
|||
#mem execute(mem$) |
|||
data "1","George","Redding","2","Fred","Oregon","3","Ben","Seneca","4","Steve","Fargo","5","Frank","Houston" |
|||
for i = 1 to 5 ' read data and place in memory DB |
|||
read num$ :read name$: read city$ |
|||
#mem execute("INSERT INTO people VALUES(";num$;",'";name$;"','";city$;"')") |
|||
next i |
|||
#mem execute("SELECT * FROM people ORDER BY name") 'sort by name order |
|||
WHILE #mem hasanswer() |
|||
#row = #mem #nextrow() |
|||
num = #row num() |
|||
name$ = #row name$() |
|||
city$ = #row city$() |
|||
print num;" ";name$;" ";city$ |
|||
WEND</syntaxhighlight><pre>3 Ben Seneca |
|||
5 Frank Houston |
|||
2 Fred Oregon |
|||
1 George Redding |
|||
4 Steve Fargo</pre> |
|||
=={{header|Rust}}== |
|||
{{trans|Kotlin}} |
|||
<syntaxhighlight lang="rust">use std::cmp::Ordering; |
|||
#[derive(Debug)] |
|||
struct Employee { |
|||
name: String, |
|||
category: String, |
|||
} |
|||
impl Employee { |
|||
fn new(name: &str, category: &str) -> Self { |
|||
Employee { |
|||
name: name.into(), |
|||
category: category.into(), |
|||
} |
|||
} |
|||
} |
|||
impl PartialEq for Employee { |
|||
fn eq(&self, other: &Self) -> bool { |
|||
self.name == other.name |
|||
} |
|||
} |
|||
impl Eq for Employee {} |
|||
impl PartialOrd for Employee { |
|||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
|||
Some(self.cmp(other)) |
|||
} |
|||
} |
|||
impl Ord for Employee { |
|||
fn cmp(&self, other: &Self) -> Ordering { |
|||
self.name.cmp(&other.name) |
|||
} |
|||
} |
|||
fn main() { |
|||
let mut employees = vec![ |
|||
Employee::new("David", "Manager"), |
|||
Employee::new("Alice", "Sales"), |
|||
Employee::new("Joanna", "Director"), |
|||
Employee::new("Henry", "Admin"), |
|||
Employee::new("Tim", "Sales"), |
|||
Employee::new("Juan", "Admin"), |
|||
]; |
|||
employees.sort(); |
|||
for e in employees { |
|||
println!("{:<6} : {}", e.name, e.category); |
|||
} |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Alice : Sales |
|||
David : Manager |
|||
Henry : Admin |
|||
Joanna : Director |
|||
Juan : Admin |
|||
Tim : Sales</pre> |
|||
=={{header|Scala}}== |
|||
<syntaxhighlight lang="scala">case class Pair(name:String, value:Double) |
|||
val input = Array(Pair("Krypton", 83.798), Pair("Beryllium", 9.012182), Pair("Silicon", 28.0855)) |
|||
input.sortBy(_.name) // Array(Pair(Beryllium,9.012182), Pair(Krypton,83.798), Pair(Silicon,28.0855)) |
|||
// alternative versions: |
|||
input.sortBy(struct => (struct.name, struct.value)) // additional sort field (name first, then value) |
|||
input.sortWith((a,b) => a.name.compareTo(b.name) < 0) // arbitrary comparison function</syntaxhighlight> |
|||
=={{header|Seed7}}== |
|||
<syntaxhighlight lang="seed7">$ include "seed7_05.s7i"; |
|||
const type: pair is new struct |
|||
var string: name is ""; |
|||
var string: value is ""; |
|||
end struct; |
|||
const func integer: compare (in pair: pair1, in pair: pair2) is |
|||
return compare(pair1.name, pair2.name); |
|||
const func string: str (in pair: aPair) is |
|||
return "(" <& aPair.name <& ", " <& aPair.value <& ")"; |
|||
enable_output(pair); |
|||
const func pair: pair (in string: name, in string: value) is func |
|||
result |
|||
var pair: newPair is pair.value; |
|||
begin |
|||
newPair.name := name; |
|||
newPair.value := value; |
|||
end func; |
|||
var array pair: data is [] ( |
|||
pair("Joe", "5531"), |
|||
pair("Adam", "2341"), |
|||
pair("Bernie", "122"), |
|||
pair("Walter", "1234"), |
|||
pair("David", "19")); |
|||
const proc: main is func |
|||
local |
|||
var pair: aPair is pair.value; |
|||
begin |
|||
data := sort(data); |
|||
for aPair range data do |
|||
writeln(aPair); |
|||
end for; |
|||
end func;</syntaxhighlight> |
|||
Output: |
|||
<pre> |
|||
(Adam, 2341) |
|||
(Bernie, 122) |
|||
(David, 19) |
|||
(Joe, 5531) |
|||
(Walter, 1234) |
|||
</pre> |
|||
=={{header|Sidef}}== |
|||
<syntaxhighlight lang="ruby"># Declare an array of pairs |
|||
var people = [['joe', 120], ['foo', 31], ['bar', 51]]; |
|||
# Sort the array in-place by name |
|||
people.sort! {|a,b| a[0] <=> b[0] }; |
|||
# Alternatively, we can use the `.sort_by{}` method |
|||
var sorted = people.sort_by { |item| item[0] }; |
|||
# Display the sorted array |
|||
say people;</syntaxhighlight> |
|||
{{out}} |
|||
<pre>[["bar", 51], ["foo", 31], ["joe", 120]]</pre> |
|||
=={{header|Simula}}== |
|||
<syntaxhighlight lang="simula">BEGIN |
|||
CLASS COMPARABLE;; |
|||
COMPARABLE CLASS PAIR(N,V); TEXT N,V;; |
|||
CLASS COMPARATOR; |
|||
VIRTUAL: |
|||
PROCEDURE COMPARE IS |
|||
INTEGER PROCEDURE COMPARE(A, B); REF(COMPARABLE) A, B;; |
|||
BEGIN |
|||
END**OF**COMPARATOR; |
|||
COMPARATOR CLASS PAIRBYNAME; |
|||
BEGIN |
|||
INTEGER PROCEDURE COMPARE(A, B); REF(COMPARABLE) A, B; |
|||
BEGIN |
|||
COMPARE := IF A QUA PAIR.N < B QUA PAIR.N THEN -1 ELSE |
|||
IF A QUA PAIR.N > B QUA PAIR.N THEN +1 ELSE 0; |
|||
END; |
|||
END**OF**PAIRBYNAME; |
|||
PROCEDURE BUBBLESORT(A, C); NAME A; REF(COMPARABLE) ARRAY A; REF(COMPARATOR) C; |
|||
BEGIN |
|||
INTEGER LOW, HIGH, I; |
|||
BOOLEAN SWAPPED; |
|||
PROCEDURE SWAP(I, J); INTEGER I, J; |
|||
BEGIN |
|||
REF(COMPARABLE) TEMP; |
|||
TEMP :- A(I); A(I) :- A(J); A(J) :- TEMP; |
|||
END**OF**SWAP; |
|||
LOW := LOWERBOUND(A, 1); |
|||
HIGH := UPPERBOUND(A, 1); |
|||
SWAPPED := TRUE; |
|||
WHILE SWAPPED DO |
|||
BEGIN |
|||
SWAPPED := FALSE; |
|||
FOR I := LOW + 1 STEP 1 UNTIL HIGH DO |
|||
BEGIN |
|||
COMMENT IF THIS PAIR IS OUT OF ORDER ; |
|||
IF C.COMPARE(A(I - 1), A(I)) > 0 THEN |
|||
BEGIN |
|||
COMMENT SWAP THEM AND REMEMBER SOMETHING CHANGED ; |
|||
SWAP(I - 1, I); |
|||
SWAPPED := TRUE; |
|||
END; |
|||
END; |
|||
END; |
|||
END**OF**BUBBLESORT; |
|||
COMMENT ** MAIN PROGRAM **; |
|||
REF(PAIR) ARRAY A(1:5); |
|||
INTEGER I; |
|||
A(1) :- NEW PAIR( "JOE", "5531" ); |
|||
A(2) :- NEW PAIR( "ADAM", "2341" ); |
|||
A(3) :- NEW PAIR( "BERNIE", "122" ); |
|||
A(4) :- NEW PAIR( "WALTER", "1234" ); |
|||
A(5) :- NEW PAIR( "DAVID", "19" ); |
|||
BUBBLESORT(A, NEW PAIRBYNAME); |
|||
FOR I:= 1 STEP 1 UNTIL 5 DO |
|||
BEGIN OUTTEXT(A(I).N); OUTCHAR(' '); OUTTEXT(A(I).V); OUTIMAGE; END; |
|||
OUTIMAGE; |
|||
END.</syntaxhighlight> |
|||
{{out}} |
|||
<pre>ADAM 2341 |
|||
BERNIE 122 |
|||
DAVID 19 |
|||
JOE 5531 |
|||
WALTER 1234</pre> |
|||
=={{header|SQL}}== |
|||
We can treat the array of data structures as a table. An <code>order by</code> clause in a query will sort the data.<syntaxhighlight lang="sql">-- setup |
|||
create table pairs (name varchar(16), value varchar(16)); |
|||
insert into pairs values ('Fluffy', 'cat'); |
|||
insert into pairs values ('Fido', 'dog'); |
|||
insert into pairs values ('Francis', 'fish'); |
|||
-- order them by name |
|||
select * from pairs order by name;</syntaxhighlight> |
|||
{{out}} |
|||
<pre>NAME VALUE |
|||
---------------- ---------------- |
|||
Fido dog |
|||
Fluffy cat |
|||
Francis fish</pre> |
|||
=={{header|Swift}}== |
|||
<syntaxhighlight lang="swift">extension Sequence { |
|||
func sorted<Value>( |
|||
on: KeyPath<Element, Value>, |
|||
using: (Value, Value) -> Bool |
|||
) -> [Element] where Value: Comparable { |
|||
return withoutActuallyEscaping(using, do: {using -> [Element] in |
|||
return self.sorted(by: { using($0[keyPath: on], $1[keyPath: on]) }) |
|||
}) |
|||
} |
|||
} |
|||
struct Person { |
|||
var name: String |
|||
var role: String |
|||
} |
|||
let a = Person(name: "alice", role: "manager") |
|||
let b = Person(name: "bob", role: "worker") |
|||
let c = Person(name: "charlie", role: "driver") |
|||
print([c, b, a].sorted(on: \.name, using: <))</syntaxhighlight> |
|||
{{out}} |
|||
<pre>[Runner.Person(name: "alice", role: "manager"), Runner.Person(name: "bob", role: "worker"), Runner.Person(name: "charlie", role: "driver")]</pre> |
|||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
Modeling the data structure being sorted as a list (a common Tcl practice): |
Modeling the data structure being sorted as a list (a common Tcl practice): |
||
< |
<syntaxhighlight lang="tcl">set people {{joe 120} {foo 31} {bar 51}} |
||
# sort by the first element of each pair |
# sort by the first element of each pair |
||
lsort -index 0 $people</ |
lsort -index 0 $people</syntaxhighlight> |
||
=={{header|UNIX Shell}}== |
|||
With this language, everything is a string. My list of pairs is a string where a colon ":" separates "name:value", and a newline separates different pairs. Then I can use <tt>sort -t: -k1,1</tt> to sort the pairs by name. |
|||
<syntaxhighlight lang="bash">list="namez:order! |
|||
name space:in |
|||
name1:sort |
|||
name:Please" |
|||
newline=" |
|||
" |
|||
dumplist() { |
|||
( |
|||
IFS=$newline |
|||
for pair in $list; do |
|||
( |
|||
IFS=: |
|||
set -- $pair |
|||
echo " $1 => $2" |
|||
) |
|||
done |
|||
) |
|||
} |
|||
echo "Original list:" |
|||
dumplist |
|||
list=`IFS=$newline; printf %s "$list" | sort -t: -k1,1` |
|||
echo "Sorted list:" |
|||
dumplist</syntaxhighlight> |
|||
Output: <pre>Original list: |
|||
namez => order! |
|||
name space => in |
|||
name1 => sort |
|||
name => Please |
|||
Sorted list: |
|||
name => Please |
|||
name space => in |
|||
name1 => sort |
|||
namez => order!</pre> |
|||
=={{header|Ursala}}== |
=={{header|Ursala}}== |
||
Line 721: | Line 4,774: | ||
The built in sort operator, -<, can be parameterized by an |
The built in sort operator, -<, can be parameterized by an |
||
anonymous field specification and/or a relational predicate. |
anonymous field specification and/or a relational predicate. |
||
< |
<syntaxhighlight lang="ursala">#import std |
||
#cast %sWLW |
#cast %sWLW |
||
Line 729: | Line 4,782: | ||
( |
( |
||
-<&l <('z','a'),('x','c'),('y','b')>, # sorted by the left |
-<&l <('z','a'),('x','c'),('y','b')>, # sorted by the left |
||
-<&r <('z','a'),('x','c'),('y','b')>) # sorted by the right</ |
-<&r <('z','a'),('x','c'),('y','b')>) # sorted by the right</syntaxhighlight> |
||
output: |
output: |
||
<pre>( |
<pre>( |
||
Line 737: | Line 4,790: | ||
a more verbose example, showing a list of records of a user defined type sorted by a named field: |
a more verbose example, showing a list of records of a user defined type sorted by a named field: |
||
< |
<syntaxhighlight lang="ursala">#import std |
||
person :: name %s value %s |
person :: name %s value %s |
||
Line 744: | Line 4,797: | ||
< |
< |
||
person[name: ' |
person[name: 'Marilyn Monroe',value: 'priceless'], |
||
person[name: 'Victor Hugo',value: 'millions'], |
person[name: 'Victor Hugo',value: 'millions'], |
||
person[name: 'Johnny Carson',value: 'up there']> |
person[name: 'Johnny Carson',value: 'up there']> |
||
Line 750: | Line 4,803: | ||
#cast _person%L |
#cast _person%L |
||
example = (lleq+ ~name~~)-< people</ |
example = (lleq+ ~name~~)-< people</syntaxhighlight> |
||
output: |
output: |
||
<pre> |
<pre> |
||
< |
< |
||
person[name: 'Johnny Carson',value: 'up there'], |
person[name: 'Johnny Carson',value: 'up there'], |
||
person[name: ' |
person[name: 'Marilyn Monroe',value: 'priceless'], |
||
person[name: 'Victor Hugo',value: 'millions']></pre> |
person[name: 'Victor Hugo',value: 'millions']></pre> |
||
=={{header|Wren}}== |
|||
{{libheader|Wren-sort}} |
|||
<syntaxhighlight lang="wren">import "./sort" for Cmp, Sort, Comparable |
|||
class Pair is Comparable { |
|||
construct new (name, value) { |
|||
_name = name |
|||
_value = value |
|||
} |
|||
name { _name } |
|||
value { _value } |
|||
compare(other) { Cmp.string.call(_name, other.name) } |
|||
toString { "{%(_name), %(_value)}" } |
|||
} |
|||
var pairs = [ |
|||
Pair.new("grass", "green"), |
|||
Pair.new("snow", "white"), |
|||
Pair.new("sky", "blue"), |
|||
Pair.new("cherry", "red") |
|||
] |
|||
System.print("Before sorting:") |
|||
System.print(" " + pairs.join("\n ")) |
|||
Sort.insertion(pairs) |
|||
System.print("\nAfter sorting:") |
|||
System.print(" " + pairs.join("\n "))</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Before sorting: |
|||
{grass, green} |
|||
{snow, white} |
|||
{sky, blue} |
|||
{cherry, red} |
|||
After sorting: |
|||
{cherry, red} |
|||
{grass, green} |
|||
{sky, blue} |
|||
{snow, white} |
|||
</pre> |
|||
=={{header|XPL0}}== |
|||
<syntaxhighlight lang="xpl0">include c:\cxpl\stdlib; |
|||
char Dict(10,10); |
|||
int Entries; |
|||
proc BSort(A, N); \Bubble sort array A's key string into ascending order |
|||
char A; \address of array |
|||
int N; \number of items in array (size) |
|||
int B, I, J, T; |
|||
[B:= A; \B(I) accesses 32-bit pointers, not A(I) 8-bit bytes |
|||
for J:= N-1 downto 0 do |
|||
for I:= 0 to J-1 do |
|||
if StrCmp(A(I,1), A(I+1,1)) > 0 then |
|||
[T:= B(I); B(I):= B(I+1); B(I+1):= T]; \swap pointers |
|||
]; |
|||
proc AddEntry(Letter, Greek); \Insert entry into associative array |
|||
char Letter, Greek; |
|||
[Dict(Entries,0):= Letter; |
|||
StrCopy(Greek, @Dict(Entries,1)); |
|||
Entries:= Entries+1; \(limit checks ignored for simplicity) |
|||
]; |
|||
int I; |
|||
[Entries:= 0; |
|||
AddEntry(^A, "alpha"); \add items in arbitrary order |
|||
AddEntry(^D, "delta"); |
|||
AddEntry(^B, "beta"); |
|||
AddEntry(^C, "gamma"); |
|||
BSort(Dict, Entries); \sort entries by Greek name |
|||
for I:= 0 to Entries-1 do \show sorted entries |
|||
[ChOut(0, Dict(I,0)); ChOut(0, ^ ); Text(0, @Dict(I,1)); CrLf(0)]; |
|||
]</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
A alpha |
|||
B beta |
|||
D delta |
|||
C gamma |
|||
</pre> |
|||
=={{header|zkl}}== |
|||
The list of lists way is available or: |
|||
<syntaxhighlight lang="zkl">class P{var name,value; |
|||
fcn init(nm,val){name,value=vm.arglist} |
|||
fcn __opLT(p){name<p.name} // implementation of P1 < P2 |
|||
} |
|||
// create list of pairs: |
|||
p:=List(P("sam","a"),P("fred","b"),P("chris","c")); |
|||
p.sort(); |
|||
p.apply("name"); //-->L("chris","fred","sam")</syntaxhighlight> |
Latest revision as of 13:22, 6 August 2024
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
You are encouraged to solve this task according to the task description, using any language you may know.
Sorting Algorithm
This is a sorting algorithm. It may be applied to a set of data in order to sort it.
For comparing various sorts, see compare sorts.
For other sorting algorithms, see sorting algorithms, or:
Heap sort | Merge sort | Patience sort | Quick sort
O(n log2n) sorts
Shell Sort
O(n2) sorts
Bubble sort |
Cocktail sort |
Cocktail sort with shifting bounds |
Comb sort |
Cycle sort |
Gnome sort |
Insertion sort |
Selection sort |
Strand sort
other sorts
Bead sort |
Bogo sort |
Common sorted list |
Composite structures sort |
Custom comparator sort |
Counting sort |
Disjoint sublist sort |
External sort |
Jort sort |
Lexicographical sort |
Natural sorting |
Order by pair comparisons |
Order disjoint list items |
Order two numerical lists |
Object identifier (OID) sort |
Pancake sort |
Quickselect |
Permutation sort |
Radix sort |
Ranking methods |
Remove duplicate elements |
Sleep sort |
Stooge sort |
[Sort letters of a string] |
Three variable sort |
Topological sort |
Tree sort
Sort an array of composite structures by a key.
For example, if you define a composite structure that presents a name-value pair (in pseudo-code):
Define structure pair such that: name as a string value as a string
and an array of such pairs:
x: array of pairs
then define a sort routine that sorts the array x by the key name.
This task can always be accomplished with Sorting Using a Custom Comparator.
If your language is not listed here, please see the other article.
11l
T Employee
String name, category
F (name, category)
.name = name
.category = category
V employees = [
Employee(‘David’, ‘Manager’),
Employee(‘Alice’, ‘Sales’),
Employee(‘Joanna’, ‘Director’),
Employee(‘Henry’, ‘Admin’),
Employee(‘Tim’, ‘Sales’),
Employee(‘Juan’, ‘Admin’)
]
employees.sort(key' e -> e.name)
L(e) employees
print(‘#<6 : #.’.format(e.name, e.category))
- Output:
Alice : Sales David : Manager Henry : Admin Joanna : Director Juan : Admin Tim : Sales
AArch64 Assembly
/* ARM assembly AARCH64 Raspberry PI 3B */
/* program shellSort64.s */
/*******************************************/
/* Constantes file */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"
/*******************************************/
/* Structures */
/********************************************/
/* city structure */
.struct 0
city_name: //
.struct city_name + 8 // string pointer
city_habitants: //
.struct city_habitants + 8 // integer
city_end:
/*********************************/
/* Initialized data */
/*********************************/
.data
sMessResult: .asciz "Name : @ number habitants : @ \n"
szMessSortHab: .asciz "Sort table for number of habitants :\n"
szMessSortName: .asciz "Sort table for name of city :\n"
szCarriageReturn: .asciz "\n"
// cities name
szCeret: .asciz "Ceret"
szMaureillas: .asciz "Maureillas"
szTaillet: .asciz "Taillet"
szReynes: .asciz "Reynes"
szVives: .asciz "Vivés"
szBoulou: .asciz "Le Boulou"
szSaintJean: .asciz "Saint Jean Pla de Corts"
szCluses: .asciz "Les Cluses"
szAlbere: .asciz "L'Albère"
szPerthus: .asciz "Le Perthus"
.align 4
TableCities:
.quad szCluses // address name string
.quad 251 // number of habitants
.quad szCeret
.quad 7705
.quad szMaureillas
.quad 2596
.quad szBoulou
.quad 5554
.quad szSaintJean
.quad 2153
.quad szAlbere
.quad 83
.quad szVives
.quad 174
.quad szTaillet
.quad 115
.quad szPerthus
.quad 586
.quad szReynes
.quad 1354
.equ NBELEMENTS, (. - TableCities) / city_end
.skip city_end // temp area for element in shellSort
// see other soluce to use stack
// in programm arm assembly in this forum
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
sZoneConv: .skip 24
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: // entry of program
ldr x0,qAdrszMessSortHab
bl affichageMess
ldr x0,qAdrTableCities // address table
mov x1,0 // not use in routine
mov x2,NBELEMENTS // number of élements
mov x3,#city_habitants // sort by number habitants
mov x4,#'N' // numeric
bl shellSort
ldr x0,qAdrTableCities // address table
bl displayTable
ldr x0,qAdrszMessSortName
bl affichageMess
ldr x0,qAdrTableCities // address table
mov x1,0 // not use in routine
mov x2,NBELEMENTS // number of élements
mov x3,#city_name // sort by city name
mov x4,#'A' // alphanumeric
bl shellSort
ldr x0,qAdrTableCities // address table
bl displayTable
100: // standard end of the program
mov x0,0 // return code
mov x8,EXIT // request to exit program
svc 0 // perform the system call
qAdrsZoneConv: .quad sZoneConv
qAdrszCarriageReturn: .quad szCarriageReturn
qAdrsMessResult: .quad sMessResult
qAdrTableCities: .quad TableCities
qAdrszMessSortHab: .quad szMessSortHab
qAdrszMessSortName: .quad szMessSortName
/***************************************************/
/* shell Sort */
/***************************************************/
/* x0 contains the address of table */
/* x1 contains the first element but not use !! */
/* this routine use first element at index zero !!! */
/* x2 contains the number of element */
/* x3 contains the offset of sort zone */
/* x4 contains type of sort zone N = numeric A = alphanumeric */
shellSort:
stp x1,lr,[sp,-16]! // save registers
stp x2,x3,[sp,-16]! // save registers
stp x4,x5,[sp,-16]! // save registers
stp x6,x7,[sp,-16]! // save registers
stp x8,x9,[sp,-16]! // save registers
stp x10,x11,[sp,-16]! // save registers
stp x12,x13,[sp,-16]! // save registers
mov x8,x3 // save offset area sort
mov x9,x4 // save type sort
mov x7,city_end // element size
sub x12,x2,1 // index last item
mov x11,x12 // init gap = last item
1: // start loop 1
lsr x11,x11,1 // gap = gap / 2
cbz x11,100f // if gap = 0 -> end
mov x3,x11 // init loop indice 1
2: // start loop 2
mul x1,x3,x7 // offset élement
mov x2,NBELEMENTS
mul x2,x7,x2
bl copyElement
add x1,x1,x8 // + offset sort zone
ldr x4,[x0,x1] // load first value
mov x5,x3 // init loop indice 2
3: // start loop 3
cmp x5,x11 // indice < gap
blt 7f // yes -> end loop 2
sub x6,x5,x11 // index = indice - gap
mul x1,x6,x7 // compute offset
add x10,x1,x8 // + offset sort zone
ldr x2,[x0,x10] // load second value
cmp x9,#'A' // sort area alapha ?
beq 4f // yes
cmp x4,x2 // else compare numeric values
bge 7f // highter
b 6f // lower
4: // compare area alphanumeric
mov x10,#0 // counter
5:
ldrb w13,[x4,x10] // byte string 1
ldrb w6,[x2,x10] // byte string 2
cmp w13,w6
bgt 7f
blt 6f
cmp w13,#0 // end string 1
beq 7f // end comparaison
add x10,x10,#1 // else add 1 in counter
b 5b // and loop
6:
mul x2,x5,x7 // offset élement
bl copyElement // copy element x1 to element x2
sub x5,x5,x11 // indice = indice - gap
b 3b // and loop
7:
mov x1,NBELEMENTS
mul x1,x7,x1
mul x2,x7,x5
bl copyElement
add x3,x3,1 // increment indice 1
cmp x3,x12 // end ?
ble 2b // no -> loop 2
b 1b // yes loop for new gap
100: // end function
ldp x12,x13,[sp],16 // restaur 2 registers
ldp x10,x11,[sp],16 // restaur 2 registers
ldp x8,x9,[sp],16 // restaur 2 registers
ldp x6,x7,[sp],16 // restaur 2 registers
ldp x4,x5,[sp],16 // restaur 2 registers
ldp x2,x3,[sp],16 // restaur 2 registers
ldp x1,lr,[sp],16 // restaur 2 registers
ret // return to address lr x30
/******************************************************************/
/* copy table element */
/******************************************************************/
/* r0 contains the address of table */
/* r1 offset origin element */
/* r2 offset destination element */
copyElement:
stp x1,lr,[sp,-16]! // save registers
stp x2,x3,[sp,-16]! // save registers
stp x4,x5,[sp,-16]! // save registers
mov x3,0
add x1,x1,x0
add x2,x2,x0
1:
ldrb w4,[x1,x3]
strb w4,[x2,x3]
add x3,x3,1
cmp x3,city_end
blt 1b
100:
ldp x4,x5,[sp],16 // restaur 2 registers
ldp x2,x3,[sp],16 // restaur 2 registers
ldp x1,lr,[sp],16 // restaur 2 registers
ret // return to address lr x30
/******************************************************************/
/* Display table elements */
/******************************************************************/
/* x0 contains the address of table */
displayTable:
stp x1,lr,[sp,-16]! // save registers
stp x2,x3,[sp,-16]! // save registers
stp x4,x5,[sp,-16]! // save registers
stp x6,x7,[sp,-16]! // save registers
mov x2,x0 // table address
mov x3,0
mov x6,city_end
1: // loop display table
mul x4,x3,x6
add x4,x4,city_name
ldr x1,[x2,x4]
ldr x0,qAdrsMessResult
bl strInsertAtCharInc // put name in message
mov x5,x0 // save address of new message
mul x4,x3,x6
add x4,x4,city_habitants // and load value
ldr x0,[x2,x4]
ldr x1,qAdrsZoneConv // display value
bl conversion10 // call function
mov x0,x5
ldr x1,qAdrsZoneConv
bl strInsertAtCharInc // insert result at @ character
bl affichageMess // display message
add x3,x3,1
cmp x3,#NBELEMENTS - 1
ble 1b
ldr x0,qAdrszCarriageReturn
bl affichageMess
100:
ldp x6,x7,[sp],16 // restaur 2 registers
ldp x4,x5,[sp],16 // restaur 2 registers
ldp x2,x3,[sp],16 // restaur 2 registers
ldp x1,lr,[sp],16 // restaur 2 registers
ret // return to address lr x30
/********************************************************/
/* File Include fonctions */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"
Sort table for number of habitants : Name : L'Albère number habitants : 83 Name : Taillet number habitants : 115 Name : Vivés number habitants : 174 Name : Les Cluses number habitants : 251 Name : Le Perthus number habitants : 586 Name : Reynes number habitants : 1354 Name : Saint Jean Pla de Corts number habitants : 2153 Name : Maureillas number habitants : 2596 Name : Le Boulou number habitants : 5554 Name : Ceret number habitants : 7705 Sort table for name of city : Name : Ceret number habitants : 7705 Name : L'Albère number habitants : 83 Name : Le Boulou number habitants : 5554 Name : Le Perthus number habitants : 586 Name : Les Cluses number habitants : 251 Name : Maureillas number habitants : 2596 Name : Reynes number habitants : 1354 Name : Saint Jean Pla de Corts number habitants : 2153 Name : Taillet number habitants : 115 Name : Vivés number habitants : 174
ACL2
(defun insert-by-key (o os key)
(cond ((endp os) (list o))
((< (cdr (assoc key o))
(cdr (assoc key (first os))))
(cons o os))
(t (cons (first os)
(insert-by-key o (rest os) key)))))
(defun isort-by-key (os key)
(if (endp os)
nil
(insert-by-key (first os)
(isort-by-key (rest os) key)
key)))
(isort-by-key
'(((name . "map")
(weight . 9)
(value . 150))
((name . "compass")
(weight . 13)
(value . 35))
((name . "water")
(weight . 153)
(value . 200))
((name . "sandwich")
(weight . 50)
(value . 60))
((name . "glucose")
(weight . 15)
(value . 60)))
'value)
Output:
(((NAME . "compass") (WEIGHT . 13) (VALUE . 35)) ((NAME . "glucose") (WEIGHT . 15) (VALUE . 60)) ((NAME . "sandwich") (WEIGHT . 50) (VALUE . 60)) ((NAME . "map") (WEIGHT . 9) (VALUE . 150)) ((NAME . "water") (WEIGHT . 153) (VALUE . 200)))
Action!
DEFINE PTR="CARD"
DEFINE PAIR_SIZE="4"
DEFINE PAIR_COUNT="1"
TYPE Pair=[PTR name,value]
BYTE ARRAY pairs(100)
BYTE count=[0]
PTR FUNC GetItemAddr(INT index)
PTR addr
addr=pairs+index*PAIR_SIZE
RETURN (addr)
PROC PrintArray()
INT i
Pair POINTER p
Put('[)
FOR i=0 TO count-1
DO
IF i>0 THEN Put(' ) FI
p=GetItemAddr(i)
PrintF("(%S,%S)",p.name,p.value)
OD
Put(']) PutE()
RETURN
PROC Append(CHAR ARRAY n,v)
Pair POINTER dst
dst=GetItemAddr(count)
dst.name=n
dst.value=v
count==+1
RETURN
PROC InitData()
Append("Warsaw","Poland")
Append("Prague","Czech Republic")
Append("London","United Kingdom")
Append("Paris","France")
Append("Madrit","Spain")
Append("Berlin","Germany")
Append("Rome","Italy")
Append("Moscow","Russia")
Append("Budapest","Hungary")
RETURN
PROC Sort()
INT i,j,minpos
CHAR ARRAY tmp
Pair POINTER p1,p2
FOR i=0 TO count-2
DO
minpos=i
FOR j=i+1 TO count-1
DO
p1=GetItemAddr(minpos)
p2=GetItemAddr(j)
IF SCompare(p1.name,p2.name)>0 THEN
minpos=j
FI
OD
IF minpos#i THEN
p1=GetItemAddr(minpos)
p2=GetItemAddr(i)
tmp=p1.name p1.name=p2.name p2.name=tmp
tmp=p1.value p1.value=p2.value p2.value=tmp
FI
OD
RETURN
PROC Main()
InitData()
PrintE("Array before sort:")
PrintArray() PutE()
Sort()
PrintE("Array after sort:")
PrintArray()
RETURN
- Output:
Screenshot from Atari 8-bit computer
Array before sort: [(Warsaw,Poland) (Prague,Czech Republic) (London,United Kingdom) (Paris,France) (Madrit,Spain) (Berlin,Germany) (Rome,Italy) (Moscow,Russia) (Budapest,Hungary)] Array after sort: [(Berlin,Germany) (Budapest,Hungary) (London,United Kingdom) (Madrit,Spain) (Moscow,Russia) (Paris,France) (Prague,Czech Republic) (Rome,Italy) (Warsaw,Poland)]
Ada
Ada 2005 defines 2 standard subprograms for sorting arrays - 1 for constrained arrays and 1 for unconstrained arrays. Below is a example of using the unconstrained version.
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Generic_Array_Sort;
procedure Demo_Array_Sort is
function "+" (S : String) return Unbounded_String renames To_Unbounded_String;
type A_Composite is
record
Name : Unbounded_String;
Value : Unbounded_String;
end record;
function "<" (L, R : A_Composite) return Boolean is
begin
return L.Name < R.Name;
end "<";
procedure Put_Line (C : A_Composite) is
begin
Put_Line (To_String (C.Name) & " " & To_String (C.Value));
end Put_Line;
type An_Array is array (Natural range <>) of A_Composite;
procedure Sort is new Ada.Containers.Generic_Array_Sort (Natural, A_Composite, An_Array);
Data : An_Array := (1 => (Name => +"Joe", Value => +"5531"),
2 => (Name => +"Adam", Value => +"2341"),
3 => (Name => +"Bernie", Value => +"122"),
4 => (Name => +"Walter", Value => +"1234"),
5 => (Name => +"David", Value => +"19"));
begin
Sort (Data);
for I in Data'Range loop
Put_Line (Data (I));
end loop;
end Demo_Array_Sort;
Result:
C:\Ada\sort_composites\lib\demo_array_sort Adam 2341 Bernie 122 David 19 Joe 5531 Walter 1234
Ada 2005 also provides ordered containers, so no explicit call is required. Here is an example of an ordered set:
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Ordered_Sets;
procedure Sort_Composites is
function "+" (S : String) return Unbounded_String renames To_Unbounded_String;
type A_Composite is
record
Name : Unbounded_String;
Value : Unbounded_String;
end record;
function "<" (L, R : A_Composite) return Boolean is
begin
return L.Name < R.Name;
end "<";
procedure Put_Line (C : A_Composite) is
begin
Put_Line (To_String (C.Name) & " " & To_String (C.Value));
end Put_Line;
package Composite_Sets is new Ada.Containers.Ordered_Sets (A_Composite);
procedure Put_Line (C : Composite_Sets.Cursor) is
begin
Put_Line (Composite_Sets.Element (C));
end Put_Line;
Data : Composite_Sets.Set;
begin
Data.Insert (New_Item => (Name => +"Joe", Value => +"5531"));
Data.Insert (New_Item => (Name => +"Adam", Value => +"2341"));
Data.Insert (New_Item => (Name => +"Bernie", Value => +"122"));
Data.Insert (New_Item => (Name => +"Walter", Value => +"1234"));
Data.Insert (New_Item => (Name => +"David", Value => +"19"));
Data.Iterate (Put_Line'Access);
end Sort_Composites;
Result:
C:\Ada\sort_composites\lib\sort_composites Adam 2341 Bernie 122 David 19 Joe 5531 Walter 1234
There is no standard sort function for Ada 95. The example below implements a simple bubble sort.
with Ada.Text_Io;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
procedure Sort_Composite is
type Composite_Record is record
Name : Unbounded_String;
Value : Unbounded_String;
end record;
type Pairs_Array is array(Positive range <>) of Composite_Record;
procedure Swap(Left, Right : in out Composite_Record) is
Temp : Composite_Record := Left;
begin
Left := Right;
Right := Temp;
end Swap;
-- Sort_Names uses a bubble sort
procedure Sort_Name(Pairs : in out Pairs_Array) is
Swap_Performed : Boolean := True;
begin
while Swap_Performed loop
Swap_Performed := False;
for I in Pairs'First..(Pairs'Last - 1) loop
if Pairs(I).Name > Pairs(I + 1).Name then
Swap (Pairs(I), Pairs(I + 1));
Swap_Performed := True;
end if;
end loop;
end loop;
end Sort_Name;
procedure Print(Item : Pairs_Array) is
begin
for I in Item'range loop
Ada.Text_Io.Put_Line(To_String(Item(I).Name) & ", " &
to_String(Item(I).Value));
end loop;
end Print;
type Names is (Fred, Barney, Wilma, Betty, Pebbles);
type Values is (Home, Work, Cook, Eat, Bowl);
My_Pairs : Pairs_Array(1..5);
begin
for I in My_Pairs'range loop
My_Pairs(I).Name := To_Unbounded_String(Names'Image(Names'Val(Integer(I - 1))));
My_Pairs(I).Value := To_Unbounded_String(Values'Image(Values'Val(Integer(I - 1))));
end loop;
Print(My_Pairs);
Ada.Text_Io.Put_Line("=========================");
Sort_Name(My_Pairs);
Print(My_Pairs);
end Sort_Composite;
ALGOL 68
MODE SORTSTRUCT = PERSON;
OP < = (PERSON a,b)BOOL: age OF a < age OF b;
PR READ "prelude/sort.a68" PR;
MODE PERSON = STRUCT (STRING name, INT age);
FORMAT person repr = $"Name: "g", Age: "g(0)l$;
[]SORTSTRUCT person = (("joe", 120), ("foo", 31), ("bar", 51));
printf((person repr, shell sort(person), $l$))
Output:
Name: foo, Age: 31 Name: bar, Age: 51 Name: joe, Age: 120
AppleScript
macOS Yosemite onwards, for import of Foundation framework
use framework "Foundation"
----- SORTING COMPOSITE STRUCTURES (BY MULTIPLE KEYS) ------
-- List of {strKey, blnAscending} pairs -> list of records -> sorted list of records
-- sortByComparing :: [(String, Bool)] -> [Record] -> [Record]
on sortByComparing(keyDirections, xs)
set ca to current application
script recDict
on |λ|(x)
ca's NSDictionary's dictionaryWithDictionary:x
end |λ|
end script
set dcts to map(recDict, xs)
script asDescriptor
on |λ|(kd)
set {k, d} to kd
ca's NSSortDescriptor's sortDescriptorWithKey:k ascending:d selector:dcts
end |λ|
end script
((ca's NSArray's arrayWithArray:dcts)'s ¬
sortedArrayUsingDescriptors:map(asDescriptor, keyDirections)) as list
end sortByComparing
--------------------------- TEST ---------------------------
on run
set xs to [¬
{city:"Shanghai ", pop:24.2}, ¬
{city:"Karachi ", pop:23.5}, ¬
{city:"Beijing ", pop:21.5}, ¬
{city:"Sao Paulo ", pop:24.2}, ¬
{city:"Dhaka ", pop:17.0}, ¬
{city:"Delhi ", pop:16.8}, ¬
{city:"Lagos ", pop:16.1}]
-- Boolean true for ascending order, false for descending:
sortByComparing([{"pop", false}, {"city", true}], xs)
end run
-------------------- GENERIC FUNCTIONS ---------------------
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: Handler -> Script
on mReturn(f)
if class of f is script then
f
else
script
property |λ| : f
end script
end if
end mReturn
- Output:
{{pop:24.2, city:"Sao Paulo "}, {pop:24.2, city:"Shanghai "}, {pop:23.5, city:"Karachi "}, {pop:21.5, city:"Beijing "}, {pop:17.0, city:"Dhaka "}, {pop:16.8, city:"Delhi "}, {pop:16.1, city:"Lagos "}}
ARM Assembly
/* ARM assembly Raspberry PI */
/* program compositeSort.s */
/* REMARK 1 : this program use routines in a include file
see task Include a file language arm assembly
for the routine affichageMess conversion10
see at end of this program the instruction include */
/* for constantes see task include a file in arm assembly */
/************************************/
/* Constantes */
/************************************/
.include "../constantes.inc"
/*******************************************/
/* Structures */
/********************************************/
/* city structure */
.struct 0
city_name: @
.struct city_name + 4
city_habitants: @
.struct city_habitants + 4
city_end:
/*********************************/
/* Initialized data */
/*********************************/
.data
sMessResult: .asciz "Name : @ number habitants : @ \n"
szMessSortHab: .asciz "Sort table for number of habitants :\n"
szMessSortName: .asciz "Sort table for name of city :\n"
szCarriageReturn: .asciz "\n"
// cities name
szCeret: .asciz "Ceret"
szMaureillas: .asciz "Maureillas"
szTaillet: .asciz "Taillet"
szReynes: .asciz "Reynes"
szVives: .asciz "Vivés"
szBoulou: .asciz "Le Boulou"
szSaintJean: .asciz "Saint Jean Pla de Corts"
szCluses: .asciz "Les Cluses"
szAlbere: .asciz "L'Albère"
szPerthus: .asciz "Le Perthus"
.align 4
TableCities:
.int szCluses @ address name string
.int 251 @ number of habitants
.int szCeret
.int 7705
.int szMaureillas
.int 2596
.int szBoulou
.int 5554
.int szSaintJean
.int 2153
.int szAlbere
.int 83
.int szVives
.int 174
.int szTaillet
.int 115
.int szPerthus
.int 586
.int szReynes
.int 1354
.equ NBELEMENTS, (. - TableCities) / city_end
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
sZoneConv: .skip 24
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: @ entry of program
ldr r0,iAdrszMessSortHab
bl affichageMess
ldr r0,iAdrTableCities @ address city table
mov r1,#0 @ not use in routine
mov r2,#NBELEMENTS @ number of élements
mov r3,#city_habitants @ sort by number habitants
mov r4,#'N' @ Alphanumeric
bl shellSort
ldr r0,iAdrTableCities @ address number table
bl displayTable
ldr r0,iAdrszMessSortName
bl affichageMess
ldr r0,iAdrTableCities @ address city table
mov r1,#0 @ not use in routine
mov r2,#NBELEMENTS @ number of élements
mov r3,#city_name @ sort by name
mov r4,#'A' @ Alphanumeric
bl shellSort
ldr r0,iAdrTableCities @ address number table
bl displayTable
100: @ standard end of the program
mov r0, #0 @ return code
mov r7, #EXIT @ request to exit program
svc #0 @ perform the system call
iAdrszCarriageReturn: .int szCarriageReturn
iAdrsMessResult: .int sMessResult
iAdrTableCities: .int TableCities
iAdrszMessSortHab: .int szMessSortHab
iAdrszMessSortName: .int szMessSortName
/***************************************************/
/* shell Sort */
/***************************************************/
/* r0 contains the address of table */
/* r1 contains the first element but not use !! */
/* this routine use first element at index zero !!! */
/* r2 contains the number of element */
/* r3 contains the offset of sort zone */
/* r4 contains type of sort zone N = numeric A = alphanumeric */
shellSort:
push {r0-r12,lr} @ save registers
sub sp,#city_end @ reserve area on stack
mov fp,sp @ frame pointer = stack
mov r8,r3 @ save offser area sort
mov r9,r4 @ save type sort
mov r7,#city_end @ element size
//vidregtit debut
sub r12,r2,#1 @ index last item
mov r6,r12 @ init gap = last item
1: @ start loop 1
lsrs r6,#1 @ gap = gap / 2
beq 100f @ if gap = 0 -> end
mov r3,r6 @ init loop indice 1
2: @ start loop 2
mul r1,r3,r7 @ offset élement
mov r2,fp @ save on stack
bl saveElement
add r1,r8 @ + offset sort zone
ldr r4,[r0,r1] @ load first value
mov r5,r3 @ init loop indice 2
3: @ start loop 3
cmp r5,r6 @ indice < gap
blt 8f @ yes -> end loop 2
sub r10,r5,r6 @ index = indice - gap
mul r1,r10,r7 @ offset élement
add r10,r1,r8 @ + offset sort zone
ldr r2,[r0,r10] @ load second value
push {r3,r5} @ save registrars because not enought register
cmp r9,#'A' @ sort area alapha ?
beq 4f @ yes
cmp r4,r2 @ else compare numeric values
bge 7f @ highter
b 6f @ lower
4: @ compare area alphanumeric
mov r10,#0 @ counter
5:
ldrb r3,[r4,r10] @ byte string 1
ldrb r5,[r2,r10] @ byte string 2
cmp r3,r5
bgt 7f
blt 6f
cmp r3,#0 @ end string 1
beq 7f @ ens comparaison
add r10,r10,#1 @ else add 1 in counter
b 5b @ and loop
6:
pop {r3,r5} @ restaur registers
mul r2,r5,r7 @ offset élement
bl copyElement @ copy element r1 to element r2
sub r5,r6 @ indice = indice - gap
b 3b @ and loop
7:
pop {r3,r5}
8: @ end loop 3
mul r1,r5,r7 @ offset destination élement
mov r2,fp @ restaur element in table
bl restaurElement
add r3,#1 @ increment indice 1
cmp r3,r12 @ end ?
ble 2b @ no -> loop 2
b 1b @ yes loop for new gap
100: @ end function
add sp,#city_end
pop {r0-r12,lr} @ restaur registers
bx lr @ return
/******************************************************************/
/* copy table element */
/******************************************************************/
/* r0 contains the address of table */
/* r1 offset origin element */
/* r2 offset destination element */
copyElement:
push {r0-r4,lr} @ save registers
//vidregtit copy
mov r3,#0
add r1,r0
add r2,r0
1:
ldrb r4,[r1,r3]
strb r4,[r2,r3]
add r3,#1
cmp r3,#city_end
blt 1b
100:
pop {r0-r4,lr}
bx lr
/******************************************************************/
/* save element */
/******************************************************************/
/* r0 contains the address of table */
/* r1 offset origin element */
/* r2 address destination */
saveElement:
push {r0-r4,lr} @ save registers
mov r3,#0
add r1,r0
1:
ldrb r4,[r1,r3]
strb r4,[r2,r3]
add r3,#1
cmp r3,#city_end
blt 1b
100:
pop {r0-r4,lr}
bx lr
/******************************************************************/
/* restaur element */
/******************************************************************/
/* r0 contains the address of table */
/* r1 offset destination element */
/* r2 address origine */
restaurElement:
push {r0-r4,lr} @ save registers
mov r3,#0
add r1,r0
1:
ldrb r4,[r2,r3]
strb r4,[r1,r3]
add r3,#1
cmp r3,#city_end
blt 1b
100:
pop {r0-r4,lr}
bx lr
/******************************************************************/
/* Display table elements */
/******************************************************************/
/* r0 contains the address of table */
displayTable:
push {r0-r6,lr} @ save registers
mov r2,r0 @ table address
mov r3,#0
mov r6,#city_end
1: @ loop display table
mul r4,r3,r6
add r4,#city_name
ldr r1,[r2,r4]
ldr r0,iAdrsMessResult
bl strInsertAtCharInc @ put name in message
mov r5,r0 @ save address of new message
mul r4,r3,r6
add r4,#city_habitants @ and load value
ldr r0,[r2,r4]
ldr r1,iAdrsZoneConv
bl conversion10 @ call decimal conversion
mov r0,r5
ldr r1,iAdrsZoneConv @ insert conversion in message
bl strInsertAtCharInc
bl affichageMess @ display message
add r3,#1
cmp r3,#NBELEMENTS - 1
ble 1b
ldr r0,iAdrszCarriageReturn
bl affichageMess
100:
pop {r0-r6,lr}
bx lr
iAdrsZoneConv: .int sZoneConv
/***************************************************/
/* ROUTINES INCLUDE */
/***************************************************/
.include "../affichage.inc"
Sort table for number of habitants : Name : L'Albère number habitants : 83 Name : Taillet number habitants : 115 Name : Vivés number habitants : 174 Name : Les Cluses number habitants : 251 Name : Le Perthus number habitants : 586 Name : Reynes number habitants : 1354 Name : Saint Jean Pla de Corts number habitants : 2153 Name : Maureillas number habitants : 2596 Name : Le Boulou number habitants : 5554 Name : Ceret number habitants : 7705 Sort table for name of city : Name : Ceret number habitants : 7705 Name : L'Albère number habitants : 83 Name : Le Boulou number habitants : 5554 Name : Le Perthus number habitants : 586 Name : Les Cluses number habitants : 251 Name : Maureillas number habitants : 2596 Name : Reynes number habitants : 1354 Name : Saint Jean Pla de Corts number habitants : 2153 Name : Taillet number habitants : 115 Name : Vivés number habitants : 174
Arturo
people: [
["joe" 120]
["foo" 31]
["bar" 51]
]
print arrange people 'x -> x\0
- Output:
[bar 51] [foo 31] [joe 120]
ATS
#include "share/atspre_staload.hats"
typedef pair =
'{
name = string,
value = string
}
fn
sort_pairs {n : int}
(pairs : &array (pair, n) >> _,
n : size_t n)
:<!wrt> void =
let
implement
array_quicksort$cmp<pair> (x, y) =
strcmp (x.name, y.name)
in
array_quicksort<pair> (pairs, n)
end
implement
main0 () =
let
val pairs_list : list (pair, 9) =
$list
('{name = "Warsaw", value = "Poland"},
'{name = "Prague", value = "Czech Republic"},
'{name = "London", value = "United Kingdom"},
'{name = "Paris", value = "France"},
'{name = "Madrid", value = "Spain"},
'{name = "Berlin", value = "Germany"},
'{name = "Rome", value = "Italy"},
'{name = "Moscow", value = "Russia"},
'{name = "Budapest", value = "Hungary"})
var pairs_array : @[pair][9]
val () = array_initize_list<pair> (pairs_array, 9, pairs_list)
val () = sort_pairs (pairs_array, i2sz 9)
var i : [i : nat | i <= 9] int i
in
for (i := 0; i <> 9; i := succ i)
println! (pairs_array[i].name, " -> ", pairs_array[i].value)
end
- Output:
$ patscc -DATS_MEMALLOC_GCBDW -O3 sort_composite_structures.dats -lgc && ./a.out Berlin -> Germany Budapest -> Hungary London -> United Kingdom Madrid -> Spain Moscow -> Russia Paris -> France Prague -> Czech Republic Rome -> Italy Warsaw -> Poland
AutoHotkey
built ListView Gui, contains a table sorting function which can be used for this.
start:
Gui, Add, ListView, r20 w200, 1|2
data =
(
foo,53
joe,34
bar,23
)
Loop, parse, data, `n
{
stringsplit, row, A_LoopField, `,
LV_Add(row, row1, row2)
}
LV_ModifyCol() ; Auto-size columns
Gui, Show
msgbox, sorting by column1
LV_ModifyCol(1, "sort") ; sort by first column
msgbox, sorting by column2
LV_ModifyCol(2, "sort Integer") ; sort by second column numerically
return
GuiClose:
ExitApp
AWK
# syntax: GAWK -f SORT_AN_ARRAY_OF_COMPOSITE_STRUCTURES.AWK
BEGIN {
# AWK lacks structures but one can be simulated using an associative array.
arr["eight 8 "]
arr["two 2 "]
arr["five 5 "]
arr["nine 9 "]
arr["one 1 "]
arr["three 3 "]
arr["six 6 "]
arr["seven 7 "]
arr["four 4 "]
arr["ten 10"]
arr["zero 0 "]
arr["twelve 12"]
arr["minus2 -2"]
show(1,7,"@val_str_asc","name") # use name part of name-value pair
show(8,9,"@val_num_asc","value") # use value part of name-value pair
exit(0)
}
function show(a,b,sequence,description, i,x) {
PROCINFO["sorted_in"] = "@unsorted"
for (i in arr) {
x = substr(i,a,b)
sub(/ +/,"",x)
arr[i] = x
}
PROCINFO["sorted_in"] = sequence
printf("sorted by %s:",description)
for (i in arr) {
printf(" %s",arr[i])
}
printf("\n")
}
- Output:
sorted by name: eight five four minus2 nine one seven six ten three twelve two zero sorted by value: -2 0 1 2 3 4 5 6 7 8 9 10 12
Babel
First, we construct a list-of-maps and assign it to variable baz. Next, we sort baz by key "foo" and assign it to variable bop. Finally, we lookup "foo" in each map in list bop and display the resulting list of numbers - they are in sorted order.
babel> baz ([map "foo" 3 "bar" 17] [map "foo" 4 "bar" 18] [map "foo" 5 "bar" 19] [map "foo" 0 "bar" 20]) <
babel> bop baz { <- "foo" lumap ! -> "foo" lumap ! lt? } lssort ! <
babel> bop {"foo" lumap !} over ! lsnum !
( 0 3 4 5 )
The same technique works for any list of data-objects you may have. User-code can expect to have the top two elements of the stack set to be the two objects to be compared. Simply access the relevant field in each object, and then perform a comparison. For example, here is a list of pairs sorted by first element:
babel> 20 lsrange ! {1 randlf 2 rem} lssort ! 2 group ! --> this creates a shuffled list of pairs
babel> dup {lsnum !} ... --> display the shuffled list, pair-by-pair
( 11 10 )
( 15 13 )
( 12 16 )
( 17 3 )
( 14 5 )
( 4 19 )
( 18 9 )
( 1 7 )
( 8 6 )
( 0 2 )
babel> {<- car -> car lt? } lssort ! --> sort the list by first element of each pair
babel> dup {lsnum !} ... --> display the sorted list, pair-by-pair
( 0 2 )
( 1 7 )
( 4 19 )
( 8 6 )
( 11 10 )
( 12 16 )
( 14 5 )
( 15 13 )
( 17 3 )
( 18 9 )
The gpsort utility performs this kind of comparison "automagically" by leveraging the ordering of Babel's underlying data-structure. Using the shuffled list from the example above:
babel> gpsort !
babel> dup {lsnum !} ...
( 0 2 )
( 1 7 )
( 4 19 )
( 8 6 )
( 11 10 )
( 12 16 )
( 14 5 )
( 15 13 )
( 17 3 )
( 18 9 )
Note that gpsort will not work for the case where you want to sort on the second element of a list of pairs. But it will work for performing a canonical sort on numbers, arrays of numbers, lists of numbers, lists of lists, lists of arrays, arrays of lists, and so on. You should not use gpsort with strings; use lexsort or strsort instead. Here's an example of sorting a mixture of pairs and triples using gpsort:
babel> dup {lsnum !} ... --> display the shuffled list of pairs and triples
( 7 2 )
( 6 4 )
( 8 9 )
( 0 5 )
( 5 14 0 )
( 3 1 )
( 9 6 10 )
( 1 12 4 )
( 11 13 7 )
( 8 2 3 )
babel> gpsort ! --> sort the list
babel> dup {lsnum !} ... --> display the result
( 0 5 )
( 3 1 )
( 6 4 )
( 7 2 )
( 8 9 )
( 1 12 4 )
( 5 14 0 )
( 8 2 3 )
( 9 6 10 )
( 11 13 7 )
BBC BASIC
Uses the supplied SORTSALIB library.
INSTALL @lib$+"SORTSALIB"
sort% = FN_sortSAinit(0,0)
DIM pair{name$, number%}
DIM array{(10)} = pair{}
FOR i% = 1 TO DIM(array{()}, 1)
READ array{(i%)}.name$, array{(i%)}.number%
NEXT
DATA "Eight", 8, "Two", 2, "Five", 5, "Nine", 9, "One", 1
DATA "Three", 3, "Six", 6, "Seven", 7, "Four", 4, "Ten", 10
C% = DIM(array{()}, 1)
D% = 1
CALL sort%, array{()}, array{(0)}.number%, array{(0)}.name$
FOR i% = 1 TO DIM(array{()}, 1)
PRINT array{(i%)}.name$, array{(i%)}.number%
NEXT
Output:
One 1 Two 2 Three 3 Four 4 Five 5 Six 6 Seven 7 Eight 8 Nine 9 Ten 10
Bracmat
The easiest way to sort an array of elements in Bracmat is to handle it as a sum of terms. A sum, when evaluated, is automatically sorted.
( (tab=("C++",1979)+(Ada,1983)+(Ruby,1995)+(Eiffel,1985))
& out$"unsorted array:"
& lst$tab
& out$("sorted array:" !tab \n)
& out$"But tab is still unsorted:"
& lst$tab
);
Output:
unsorted array: (tab= ("C++",1979)+(Ada,1983)+(Ruby,1995)+(Eiffel,1985) ); sorted array: (Ada,1983)+(C++,1979)+(Eiffel,1985)+(Ruby,1995) But tab is still unsorted: (tab= ("C++",1979)+(Ada,1983)+(Ruby,1995)+(Eiffel,1985) );
When evaluating !tab
, the expression bound to the variable name tab
is sorted, but the unevaluated expression is still bound to tab
. An assignment binds the sorted expression to tab
:
( !tab:?tab
& out$"Now tab is sorted:"
& lst$tab
);
Output:
Now tab is sorted: (tab= (Ada,1983)+("C++",1979)+(Eiffel,1985)+(Ruby,1995) );
To sort an array that is not a sum expression, we can convert it to a sum:
( ((name.map),(weight.9),(value.150))
((name.compass),(weight.13),(value.35))
((name.water),(weight.153),(value.200))
((name.sandwich),(weight.50),(value.60))
((name.glucose),(weight.15),(value.60))
: ?array
& ( reverse
= e A
. :?A
& whl'(!arg:%?e ?arg&!e !A:?A)
& !A
)
& out$("Array before sorting:" !array \n)
& 0:?sum
& whl
' (!array:%?element ?array&!element+!sum:?sum)
& whl
' (!sum:%?element+?sum&!element !array:?array)
& out$("Array after sorting (descending order):" !array \n)
& out$("Array after sorting (ascending order):" reverse$!array \n)
);
Output:
Array before sorting: ((name.map),(weight.9),(value.150)) ((name.compass),(weight.13),(value.35)) ((name.water),(weight.153),(value.200)) ((name.sandwich),(weight.50),(value.60)) ((name.glucose),(weight.15),(value.60)) Array after sorting (descending order): ((name.water),(weight.153),(value.200)) ((name.sandwich),(weight.50),(value.60)) ((name.map),(weight.9),(value.150)) ((name.glucose),(weight.15),(value.60)) ((name.compass),(weight.13),(value.35)) Array after sorting (ascending order): ((name.compass),(weight.13),(value.35)) ((name.glucose),(weight.15),(value.60)) ((name.map),(weight.9),(value.150)) ((name.sandwich),(weight.50),(value.60)) ((name.water),(weight.153),(value.200))
Bracmat has a left to right sorting order. If an array must be sorted on another field than the first field, that other field has to be made the first field. After sorting, the fields can take their original positions.
( (Joe,5531)
(Adam,2341)
(Bernie,122)
(Walter,1234)
(David,19)
: ?array
& 0:?sum
& whl
' ( !array:(?car,?cdr) ?array
& (!cdr.!car)+!sum:?sum
)
& whl
' ( !sum:(?car.?cdr)+?sum
& (!cdr,!car) !array:?array
)
& out$("Array after sorting on second field (descending order):" !array \n)
& out
$ ( "Array after sorting on second field (ascending order):"
reverse$!array
\n
)
);
Output:
Array after sorting on second field (descending order): (Joe,5531) (Adam,2341) (Walter,1234) (Bernie,122) (David,19) Array after sorting on second field (ascending order): (David,19) (Bernie,122) (Walter,1234) (Adam,2341) (Joe,5531)
C
Using qsort, from the standard library.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct twoStringsStruct {
char * key, *value;
} sTwoStrings;
int ord( char v )
{
static char *dgts = "012345679";
char *cp;
for (cp=dgts; v != *cp; cp++);
return (cp-dgts);
}
int cmprStrgs(const sTwoStrings *s1,const sTwoStrings *s2)
{
char *p1 = s1->key;
char *p2 = s2->key;
char *mrk1, *mrk2;
while ((tolower(*p1) == tolower(*p2)) && *p1) { p1++; p2++;}
if (isdigit(*p1) && isdigit(*p2)) {
long v1, v2;
if ((*p1 == '0') ||(*p2 == '0')) {
while (p1 > s1->key) {
p1--; p2--;
if (*p1 != '0') break;
}
if (!isdigit(*p1)) {
p1++; p2++;
}
}
mrk1 = p1; mrk2 = p2;
v1 = 0;
while(isdigit(*p1)) {
v1 = 10*v1+ord(*p1);
p1++;
}
v2 = 0;
while(isdigit(*p2)) {
v2 = 10*v2+ord(*p2);
p2++;
}
if (v1 == v2)
return(p2-mrk2)-(p1-mrk1);
return v1 - v2;
}
if (tolower(*p1) != tolower(*p2))
return (tolower(*p1) - tolower(*p2));
for(p1=s1->key, p2=s2->key; (*p1 == *p2) && *p1; p1++, p2++);
return (*p1 -*p2);
}
int maxstrlen( char *a, char *b)
{
int la = strlen(a);
int lb = strlen(b);
return (la>lb)? la : lb;
}
int main()
{
sTwoStrings toBsorted[] = {
{ "Beta11a", "many" },
{ "alpha1", "This" },
{ "Betamax", "sorted." },
{ "beta3", "order" },
{ "beta11a", "strings" },
{ "beta001", "is" },
{ "beta11", "which" },
{ "beta041", "be" },
{ "beta05", "in" },
{ "beta1", "the" },
{ "beta40", "should" },
};
#define ASIZE (sizeof(toBsorted)/sizeof(sTwoStrings))
int k, maxlens[ASIZE];
char format[12];
sTwoStrings *cp;
qsort( (void*)toBsorted, ASIZE, sizeof(sTwoStrings),cmprStrgs);
for (k=0,cp=toBsorted; k < ASIZE; k++,cp++) {
maxlens[k] = maxstrlen(cp->key, cp->value);
sprintf(format," %%-%ds", maxlens[k]);
printf(format, toBsorted[k].value);
}
printf("\n");
for (k=0; k < ASIZE; k++) {
sprintf(format," %%-%ds", maxlens[k]);
printf(format, toBsorted[k].key);
}
printf("\n");
return 0;
}
Output:
This is the order in which many strings should be sorted. alpha1 beta001 beta1 beta3 beta05 beta11 Beta11a beta11a beta40 beta041 Betamax
C#
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
struct Entry
{
public Entry(string name, double value) { Name = name; Value = value; }
public string Name;
public double Value;
}
static void Main(string[] args)
{
var Elements = new List<Entry>
{
new Entry("Krypton", 83.798), new Entry("Beryllium", 9.012182), new Entry("Silicon", 28.0855),
new Entry("Cobalt", 58.933195), new Entry("Selenium", 78.96), new Entry("Germanium", 72.64)
};
var sortedElements = Elements.OrderBy(e => e.Name);
foreach (Entry e in sortedElements)
Console.WriteLine("{0,-11}{1}", e.Name, e.Value);
}
}
Output:
Beryllium 9.012182 Cobalt 58.933195 Germanium 72.64 Krypton 83.798 Selenium 78.96 Silicon 28.0855
C++
Uses C++11. Compile with
g++ -std=c++11 sort.cpp
#include <algorithm>
#include <iostream>
#include <string>
struct entry {
std::string name;
std::string value;
};
int main() {
entry array[] = { { "grass", "green" }, { "snow", "white" },
{ "sky", "blue" }, { "cherry", "red" } };
std::cout << "Before sorting:\n";
for (const auto &e : array) {
std::cout << "{" << e.name << ", " << e.value << "}\n";
}
std::sort(std::begin(array), std::end(array),
[](const entry & a, const entry & b) {
return a.name < b.name;
});
std::cout << "After sorting:\n";
for (const auto &e : array) {
std::cout << "{" << e.name << ", " << e.value << "}\n";
}
}
Output:
Before sorting: {grass, green} {snow, white} {sky, blue} {cherry, red} After sorting: {cherry, red} {grass, green} {sky, blue} {snow, white}
Clojure
Clojure has a sort-by function which takes a keyfn and a coll. It returns a sorted sequence of the items in coll, where the sort order is determined by comparing (keyfn item).
;; Gathered with Google Squared
(def *langs* [["Clojure" 2007] ["Common Lisp" 1984] ["Java" 1995] ["Haskell" 1990]
["Lisp" 1958] ["Scheme" 1975]])
user> (sort-by second *langs*) ; using a keyfn
(["Lisp" 1958] ["Scheme" 1975] ["Common Lisp" 1984] ["Haskell" 1990] ["Java" 1995] ["Clojure" 2007])
You can also supply a comparator (using compare or a sibling of <). A comparator can be used with the regular sort function or the sort-by function. In the latter case, the comparator will be used on (keyfn item) instead of item.
user> (sort #(compare (second %1) (second %2)) *langs*) ; using a comparator
(["Lisp" 1958] ["Scheme" 1975] ["Common Lisp" 1984] ["Haskell" 1990] ["Java" 1995] ["Clojure" 2007])
user> (sort-by second > *langs*) ; using a keyfn and a comparator
(["Clojure" 2007] ["Java" 1995] ["Haskell" 1990] ["Common Lisp" 1984] ["Scheme" 1975] ["Lisp" 1958])
Read the docstring of sort and sort-by for more info.
Common Lisp
In Common Lisp, the sort function takes a predicate that is used as the comparator. This parameter can be any two-argument function. Additionally, the sort function can take a keyword argument :key whose result is passed to the predicate.
Let's define a composite structure of U.S. states and average test scores.
CL-USER> (defparameter *test-scores* '(("texas" 68.9) ("ohio" 87.8) ("california" 76.2) ("new york" 88.2)) )
*TEST-SCORES*
We can sort by the state name by supplying a one-argument key function that is called by the sort function to determine the value to compare. In this case, the function is first will retrieve the state name:
CL-USER> (sort (copy-list *test-scores*) #'string-lessp :key #'first)
(("california" 76.2) ("new york" 88.2) ("ohio" 87.8) ("texas" 68.9))
we can also sort by the test scores by supplying a different key function that return the test score instead:
CL-USER> (sort (copy-list *test-scores*) #'< :key #'second)
(("texas" 68.9) ("california" 76.2) ("ohio" 87.8) ("new york" 88.2))
D
import std.stdio, std.algorithm;
struct Pair { string name, value; }
void main() {
Pair[] pairs = [{"Joe", "5531"},
{"Adam", "2341"},
{"Bernie", "122"},
{"Walter", "1234"},
{"David", "19"}];
pairs.schwartzSort!q{ a.name }.writeln;
}
- Output:
[Pair("Adam", "2341"), Pair("Bernie", "122"), Pair("David", "19"), Pair("Joe", "5531"), Pair("Walter", "1234")]
Delphi
program SortCompositeStructures;
{$APPTYPE CONSOLE}
uses SysUtils, Generics.Collections, Generics.Defaults;
type
TStructurePair = record
name: string;
value: string;
constructor Create(const aName, aValue: string);
end;
constructor TStructurePair.Create(const aName, aValue: string);
begin
name := aName;
value := aValue;
end;
var
lArray: array of TStructurePair;
begin
SetLength(lArray, 3);
lArray[0] := TStructurePair.Create('dog', 'rex');
lArray[1] := TStructurePair.Create('cat', 'simba');
lArray[2] := TStructurePair.Create('horse', 'trigger');
TArray.Sort<TStructurePair>(lArray , TDelegatedComparer<TStructurePair>.Construct(
function(const Left, Right: TStructurePair): Integer
begin
Result := CompareText(Left.Name, Right.Name);
end));
end.
E
def compareBy(keyfn) { # This ought to be in the standard library
return def comparer(a, b) {
return keyfn(a).op__cmp(keyfn(b))
}
}
def x := [
["Joe",3],
["Bill",4],
["Alice",20],
["Harry",3],
]
println(x.sort(compareBy(fn [name,_] { name })))
EchoLisp
;; sorting (name value) by name - Ignoring case
(define (name a) (first a))
(define( sort-proc a b)
(string-ci<? (name a) (name b)))
(define people
'(("😎" -42) ("albert" 33) ("Simone" 44) ("Antoinette" 42) ("elvis" 666) ("😃" 1000)))
(list-sort sort-proc people)
→ (("albert" 33) ("Antoinette" 42) ("elvis" 666) ("Simone" 44) ("😃" 1000) ("😎" -42))
Elena
ELENA 6.x :
import system'routines;
import extensions;
public program()
{
var elements := new object[]{
KeyValue.new("Krypton", 83.798r),
KeyValue.new("Beryllium", 9.012182r),
KeyValue.new("Silicon", 28.0855r),
KeyValue.new("Cobalt", 58.933195r),
KeyValue.new("Selenium", 78.96r),
KeyValue.new("Germanium", 72.64r)};
var sorted := elements.sort::(former,later => former.Key < later.Key );
sorted.forEach::(element)
{
console.printLine(element.Key," - ",element)
}
}
Elixir
defmodule Person do
defstruct name: "", value: 0
end
list = [struct(Person, [name: "Joe", value: 3]),
struct(Person, [name: "Bill", value: 4]),
struct(Person, [name: "Alice", value: 20]),
struct(Person, [name: "Harry", value: 3])]
Enum.sort(list) |> Enum.each(fn x -> IO.inspect x end)
IO.puts ""
Enum.sort_by(list, &(&1.value)) |> Enum.each(&IO.inspect &1)
- Output:
%Person{name: "Alice", value: 20} %Person{name: "Bill", value: 4} %Person{name: "Harry", value: 3} %Person{name: "Joe", value: 3} %Person{name: "Joe", value: 3} %Person{name: "Harry", value: 3} %Person{name: "Bill", value: 4} %Person{name: "Alice", value: 20}
Erlang
Any Erlang type can be compared to any Erlang type. As such, nothing special needs to be done:
1> lists:sort([{{2006,2007},"Ducks"},
{{2000,2001},"Avalanche"},
{{2002,2003},"Devils"},
{{2001,2002},"Red Wings"},
{{2003,2004},"Lightning"},
{{2004,2005},"N/A: lockout"},
{{2005,2006},"Hurricanes"},
{{1999,2000},"Devils"},
{{2007,2008},"Red Wings"},
{{2008,2009},"Penguins"}]).
[{{1999,2000},"Devils"},
{{2000,2001},"Avalanche"},
{{2001,2002},"Red Wings"},
{{2002,2003},"Devils"},
{{2003,2004},"Lightning"},
{{2004,2005},"N/A: lockout"},
{{2005,2006},"Hurricanes"},
{{2006,2007},"Ducks"},
{{2007,2008},"Red Wings"},
{{2008,2009},"Penguins"}]
It is also possible to sort with custom functions, in this case by the team's name:
2> F = fun({_,X},{_,Y}) -> X < Y end.
#Fun<erl_eval.12.113037538>
3> lists:usort(F, [{{2006,2007},"Ducks"},
{{2000,2001},"Avalanche"},
{{2002,2003},"Devils"},
{{2001,2002},"Red Wings"},
{{2003,2004},"Lightning"},
{{2004,2005},"N/A: lockout"},
{{2005,2006},"Hurricanes"},
{{1999,2000},"Devils"},
{{2007,2008},"Red Wings"},
{{2008,2009},"Penguins"}]).
[{{2000,2001},"Avalanche"},
{{1999,2000},"Devils"},
{{2002,2003},"Devils"},
{{2006,2007},"Ducks"},
{{2005,2006},"Hurricanes"},
{{2003,2004},"Lightning"},
{{2004,2005},"N/A: lockout"},
{{2008,2009},"Penguins"},
{{2007,2008},"Red Wings"},
{{2001,2002},"Red Wings"}]
Euphoria
include sort.e
include misc.e
constant NAME = 1
function compare_names(sequence a, sequence b)
return compare(a[NAME],b[NAME])
end function
sequence s
s = { { "grass", "green" },
{ "snow", "white" },
{ "sky", "blue" },
{ "cherry", "red" } }
pretty_print(1,custom_sort(routine_id("compare_names"),s),{2})
Output:
{ { "cherry", "red" }, { "grass", "green" }, { "sky", "blue" }, { "snow", "white" } }
F#
F# has sortBy
functions that work on collection types for this purpose. An example using an array of pairs:
let persons = [| ("Joe", 120); ("foo", 31); ("bar", 51) |]
Array.sortInPlaceBy fst persons
printfn "%A" persons
Output:
[|("Joe", 120); ("bar", 51); ("foo", 31)|]
An example using a list of records:
type Person = { name:string; id:int }
let persons2 = [{name="Joe"; id=120}; {name="foo"; id=31}; {name="bar"; id=51}]
let sorted = List.sortBy (fun p -> p.id) persons2
for p in sorted do printfn "%A" p
Output:
{name = "foo"; id = 31;} {name = "bar"; id = 51;} {name = "Joe"; id = 120;}
Factor
This is essentially the same as Sorting Using a Custom Comparator.
TUPLE: example-pair name value ;
: sort-by-name ( seq -- seq' ) [ [ name>> ] compare ] sort ;
( scratchpad ) { T{ example-pair f "omega" "a" } T{ example-pair f "gamma" "q" } T{ example-pair f "alpha" "z" } } sort-by-name . { T{ example-pair { name "alpha" } { value "z" } } T{ example-pair { name "gamma" } { value "q" } } T{ example-pair { name "omega" } { value "a" } } }
Fantom
Any object can be sorted as needed by passing an appropriate block to the 'sort' method.
class Pair // create a composite structure
{
Str name
Str value
new make (Str name, Str value)
{
this.name = name
this.value = value
}
override Str toStr ()
{
"(Pair: $name, $value)"
}
}
class Main
{
public static Void main ()
{
// samples
pairs := [Pair("Fantom", "OO"), Pair("Clojure", "Functional"), Pair("Java", "OO") ]
sorted := pairs.dup // make a copy of original list
sorted.sort |Pair a, Pair b -> Int| // sort using custom comparator
{
a.name <=> b.name
}
echo ("Started with : " + pairs.join(" "))
echo ("Finished with: " + sorted.join(" "))
}
}
Fortran
Standard Fortran has no built-in sort function although some compilers add them. The following example uses an insertion sort.
PROGRAM EXAMPLE
IMPLICIT NONE
TYPE Pair
CHARACTER(6) :: name
CHARACTER(1) :: value
END TYPE Pair
TYPE(Pair) :: rcc(10), temp
INTEGER :: i, j
rcc(1) = Pair("Black", "0")
rcc(2) = Pair("Brown", "1")
rcc(3) = Pair("Red", "2")
rcc(4) = Pair("Orange", "3")
rcc(5) = Pair("Yellow", "4")
rcc(6) = Pair("Green", "5")
rcc(7) = Pair("Blue", "6")
rcc(8) = Pair("Violet", "7")
rcc(9) = Pair("Grey", "8")
rcc(10) = Pair("White", "9")
DO i = 2, SIZE(rcc)
j = i - 1
temp = rcc(i)
DO WHILE (j>=1 .AND. LGT(rcc(j)%name, temp%name))
rcc(j+1) = rcc(j)
j = j - 1
END DO
rcc(j+1) = temp
END DO
WRITE (*,"(2A6)") rcc
END PROGRAM EXAMPLE
Output
Black 0 Blue 6 Brown 1 Green 5 Grey 8 Orange 3 Red 2 Violet 7 White 9 Yellow 4
FreeBASIC
' FB 1.05.0 Win64
Type Pair
As String name, value
Declare Constructor(name_ As String, value_ As String)
Declare Operator Cast() As String
End Type
Constructor Pair(name_ As String, value_ As String)
name = name_
value = value_
End Constructor
Operator Pair.Cast() As String
Return "[" + name + ", " + value + "]"
End Operator
' selection sort, quick enough for sorting small number of pairs
Sub sortPairsByName(p() As Pair)
Dim As Integer i, j, m
For i = LBound(p) To UBound(p) - 1
m = i
For j = i + 1 To UBound(p)
If p(j).name < p(m).name Then m = j
Next j
If m <> i Then Swap p(i), p(m)
Next i
End Sub
Dim As Pair pairs(1 To 4) = _
{ _
Pair("grass", "green"), _
Pair("snow", "white" ), _
Pair("sky", "blue"), _
Pair("cherry", "red") _
}
Print "Before sorting :"
For i As Integer = 1 To 4
Print Tab(3); pairs(i)
Next
sortPairsByName pairs()
Print
Print "After sorting by name :"
For i As Integer = 1 To 4
Print Tab(3); pairs(i)
Next
Print
Print "Press any key to quit"
Sleep
- Output:
Before sorting : [grass, green] [snow, white] [sky, blue] [cherry, red] After sorting by name : [cherry, red] [grass, green] [sky, blue] [snow, white]
Frink
Frink's lexicalCompare[a, b, language]
function can sort strings in a lexicographically correct way for many human languages by specifying a language specifier like "da" for Danish. This allows sort routines to magically work correctly for many human languages.
class Pair
{
var name
var value
new[name is string, value is string] :=
{
this.name = name
this.value = value
}
}
a = [new Pair["one", "1"], new Pair["two", "2"], new Pair["three", "3"]]
sort[a, {|a,b| lexicalCompare[a.name, b.name]}]
- Output:
[Pair { name = one value = 1 } , Pair { name = three value = 3 } , Pair { name = two value = 2 } ]
Fōrmulæ
Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text. Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for storage and transfer purposes more than visualization and edition.
Programs in Fōrmulæ are created/edited online in its website.
In this page you can see and run the program(s) related to this task and their results. You can also change either the programs or the parameters they are called with, for experimentation, but remember that these programs were created with the main purpose of showing a clear solution of the task, and they generally lack any kind of validation.
Solution
In the following example, it is assumed that the key is the first element of each pair.
Go
package main
import (
"fmt"
"sort"
)
type pair struct {
name, value string
}
type csArray []pair
// three methods satisfy sort.Interface
func (a csArray) Less(i, j int) bool { return a[i].name < a[j].name }
func (a csArray) Len() int { return len(a) }
func (a csArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
var x = csArray{
pair{"joe", "120"},
pair{"foo", "31"},
pair{"bar", "251"},
}
func main() {
sort.Sort(x)
for _, p := range x {
fmt.Printf("%5s: %s\n", p.name, p.value)
}
}
Groovy
class Holiday {
def date
def name
Holiday(dateStr, name) { this.name = name; this.date = format.parse(dateStr) }
String toString() { "${format.format date}: ${name}" }
static format = new java.text.SimpleDateFormat("yyyy-MM-dd")
}
def holidays = [ new Holiday("2009-12-25", "Christmas Day"),
new Holiday("2009-04-22", "Earth Day"),
new Holiday("2009-09-07", "Labor Day"),
new Holiday("2009-07-04", "Independence Day"),
new Holiday("2009-10-31", "Halloween"),
new Holiday("2009-05-25", "Memorial Day"),
new Holiday("2009-03-14", "PI Day"),
new Holiday("2009-01-01", "New Year's Day"),
new Holiday("2009-12-31", "New Year's Eve"),
new Holiday("2009-11-26", "Thanksgiving"),
new Holiday("2009-02-14", "St. Valentine's Day"),
new Holiday("2009-03-17", "St. Patrick's Day"),
new Holiday("2009-01-19", "Martin Luther King Day"),
new Holiday("2009-02-16", "President's Day") ]
holidays.sort { x, y -> x.date <=> y.date }
holidays.each { println it }
Output:
2009-01-01: New Year's Day 2009-01-19: Martin Luther King Day 2009-02-14: St. Valentine's Day 2009-02-16: President's Day 2009-03-14: PI Day 2009-03-17: St. Patrick's Day 2009-04-22: Earth Day 2009-05-25: Memorial Day 2009-07-04: Independence Day 2009-09-07: Labor Day 2009-10-31: Halloween 2009-11-26: Thanksgiving 2009-12-25: Christmas Day 2009-12-31: New Year's Eve
Haskell
import Data.List
import Data.Function (on)
data Person =
P String
Int
deriving (Eq)
instance Show Person where
show (P name val) = "Person " ++ name ++ " with value " ++ show val
instance Ord Person where
compare (P a _) (P b _) = compare a b
pVal :: Person -> Int
pVal (P _ x) = x
people :: [Person]
people = [P "Joe" 12, P "Bob" 8, P "Alice" 9, P "Harry" 2]
main :: IO ()
main = do
mapM_ print $ sort people
putStrLn []
mapM_ print $ sortBy (on compare pVal) people
- Output:
Person Alice with value 9 Person Bob with value 8 Person Harry with value 2 Person Joe with value 12 Person Harry with value 2 Person Bob with value 8 Person Alice with value 9 Person Joe with value 12
More generally, sortBy takes any (a -> a -> Ordering) function as its first argument. A function of this kind can be derived from a simpler (b -> a) function using the higher order comparing function.
To sort a list of triples by the third element, for example:
import Data.Ord (comparing)
import Data.List (sortBy)
xs :: [(String, String, Int)]
xs =
zip3
(words "Richard John Marvin Alan Maurice James")
(words "Hamming McCarthy Minskey Perlis Wilkes Wilkinson")
[1915, 1927, 1926, 1922, 1913, 1919]
main :: IO ()
main = mapM_ print $ sortBy (comparing (\(_, _, y) -> y)) xs
- Output:
("Maurice","Wilkes",1913) ("Richard","Hamming",1915) ("James","Wilkinson",1919) ("Alan","Perlis",1922) ("Marvin","Minskey",1926) ("John","McCarthy",1927)
Icon and Unicon
The built-in procedure sortf will sort a list by the field in a records.
Sample output:
Some Orion stars by HIP# Rigel HIP 24436 Belatrix HIP 25336 Alnilam HIP 26311 Betelgeuse HIP 27989
J
The function /: sorts anything (its left argument) based on the keys supplied in its right argument. For example:
names =: ;: 'Perlis Wilkes Hamming Minsky Wilkinson McCarthy'
values=: ;: 'Alan Maurice Richard Marvin James John'
pairs =: values ,. names
pairs /: names
+-------+---------+
|Richard|Hamming |
+-------+---------+
|John |McCarthy |
+-------+---------+
|Marvin |Minsky |
+-------+---------+
|Alan |Perlis |
+-------+---------+
|Maurice|Wilkes |
+-------+---------+
|James |Wilkinson|
+-------+---------+
Alternatively, J's cross operator will use the same values for both the left and right arguments for /: but, in this case, /:~ is not desirable because that would have us sorting on the values (the first column) and only using the second column for equal names (none of which appear, here).
Java
import java.util.Arrays;
import java.util.Comparator;
public class SortComp {
public static class Pair {
public String name;
public String value;
public Pair(String n, String v) {
name = n;
value = v;
}
}
public static void main(String[] args) {
Pair[] pairs = {new Pair("06-07", "Ducks"), new Pair("00-01", "Avalanche"),
new Pair("02-03", "Devils"), new Pair("01-02", "Red Wings"),
new Pair("03-04", "Lightning"), new Pair("04-05", "lockout"),
new Pair("05-06", "Hurricanes"), new Pair("99-00", "Devils"),
new Pair("07-08", "Red Wings"), new Pair("08-09", "Penguins")};
sortByName(pairs);
for (Pair p : pairs) {
System.out.println(p.name + " " + p.value);
}
}
public static void sortByName(Pair[] pairs) {
Arrays.sort(pairs, new Comparator<Pair>() {
public int compare(Pair p1, Pair p2) {
return p1.name.compareTo(p2.name);
}
});
}
}
Output:
00-01 Avalanche 01-02 Red Wings 02-03 Devils 03-04 Lightning 04-05 lockout 05-06 Hurricanes 06-07 Ducks 07-08 Red Wings 08-09 Penguins 99-00 Devils
In Java 8, we can write the above using a lambda:
public static void sortByName(Pair[] pairs) {
Arrays.sort(pairs, (p1, p2) -> p1.name.compareTo(p2.name));
}
We can further use Comparator.comparing()
to construct the comparator from a "key" function:
public static void sortByName(Pair[] pairs) {
Arrays.sort(pairs, Comparator.comparing(p -> p.name));
}
JavaScript
ES5
var arr = [
{id: 3, value: "foo"},
{id: 2, value: "bar"},
{id: 4, value: "baz"},
{id: 1, value: 42},
{id: 5, something: "another string"} // Works with any object declaring 'id' as a number.
];
arr = arr.sort(function(a, b) {return a.id - b.id}); // Sort with comparator checking the id.
ES6
(() => {
'use strict';
// GENERIC FUNCTIONS FOR COMPARISONS
// compare :: a -> a -> Ordering
const compare = (a, b) => a < b ? -1 : (a > b ? 1 : 0);
// on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
const on = (f, g) => (a, b) => f(g(a), g(b));
// flip :: (a -> b -> c) -> b -> a -> c
const flip = f => (a, b) => f.apply(null, [b, a]);
// arrayCopy :: [a] -> [a]
const arrayCopy = (xs) => xs.slice(0);
// show :: a -> String
const show = x => JSON.stringify(x, null, 2);
// TEST
const xs = [{
name: 'Shanghai',
pop: 24.2
}, {
name: 'Karachi',
pop: 23.5
}, {
name: 'Beijing',
pop: 21.5
}, {
name: 'Sao Paulo',
pop: 24.2
}, {
name: 'Dhaka',
pop: 17.0
}, {
name: 'Delhi',
pop: 16.8
}, {
name: 'Lagos',
pop: 16.1
}]
// population :: Dictionary -> Num
const population = x => x.pop;
// name :: Dictionary -> String
const name = x => x.name;
return show({
byPopulation: arrayCopy(xs)
.sort(on(compare, population)),
byDescendingPopulation: arrayCopy(xs)
.sort(on(flip(compare), population)),
byName: arrayCopy(xs)
.sort(on(compare, name)),
byDescendingName: arrayCopy(xs)
.sort(on(flip(compare), name))
});
})();
- Output:
{ "byPopulation": [ { "name": "Lagos", "pop": 16.1 }, { "name": "Delhi", "pop": 16.8 }, { "name": "Dhaka", "pop": 17 }, { "name": "Beijing", "pop": 21.5 }, { "name": "Karachi", "pop": 23.5 }, { "name": "Shanghai", "pop": 24.2 }, { "name": "Sao Paulo", "pop": 24.2 } ], "byDescendingPopulation": [ { "name": "Shanghai", "pop": 24.2 }, { "name": "Sao Paulo", "pop": 24.2 }, { "name": "Karachi", "pop": 23.5 }, { "name": "Beijing", "pop": 21.5 }, { "name": "Dhaka", "pop": 17 }, { "name": "Delhi", "pop": 16.8 }, { "name": "Lagos", "pop": 16.1 } ], "byName": [ { "name": "Beijing", "pop": 21.5 }, { "name": "Delhi", "pop": 16.8 }, { "name": "Dhaka", "pop": 17 }, { "name": "Karachi", "pop": 23.5 }, { "name": "Lagos", "pop": 16.1 }, { "name": "Sao Paulo", "pop": 24.2 }, { "name": "Shanghai", "pop": 24.2 } ], "byDescendingName": [ { "name": "Shanghai", "pop": 24.2 }, { "name": "Sao Paulo", "pop": 24.2 }, { "name": "Lagos", "pop": 16.1 }, { "name": "Karachi", "pop": 23.5 }, { "name": "Dhaka", "pop": 17 }, { "name": "Delhi", "pop": 16.8 }, { "name": "Beijing", "pop": 21.5 } ] }
jq
In this section we will focus on JSON objects since the task description mentions keys. As an example, we will use this array:
def example:
[
{"name": "Joe", "value": 3},
{"name": "Bill", "value": 4},
{"name": "Alice", "value": 20},
{"name": "Harry", "value": 3}
];
Using sort_by builtin
jq's sort_by builtin can be used to sort by the value of a given key (whether or not it is a string), so we will first use that.
# To sort the array:
# example | sort_by(.name)
# To abbreviate the results, we will just show the names after sorting:
example | sort_by(.name) | map( .name )
- Output:
$ jq -n -c -f Sort_an_array_of_composite_structures.jq ["Alice","Bill","Harry","Joe"]
Using quicksort(cmp)
sort_by(f) can easily be implemented using quicksort(cmp) as defined at Sorting_Using_a_Custom_Comparator#jq as follows:
def quicksort_by(f): quicksort( (.[0]|f) <= (.[1]|f) );
Example:
example | quicksort_by(.name) | map( .name )
- Output:
As above.
Julia
lst = Pair[Pair("gold", "shiny"),
Pair("neon", "inert"),
Pair("sulphur", "yellow"),
Pair("iron", "magnetic"),
Pair("zebra", "striped"),
Pair("star", "brilliant"),
Pair("apple", "tasty"),
Pair("ruby", "red"),
Pair("dice", "random"),
Pair("coffee", "stimulating"),
Pair("book", "interesting")]
println("The original list: \n - ", join(lst, "\n - "))
sort!(lst; by=first)
println("\nThe list, sorted by name: \n - ", join(lst, "\n - "))
sort!(lst; by=last)
println("\nThe list, sorted by value: \n - ", join(lst, "\n - "))
- Output:
The original list: - "gold"=>"shiny" - "neon"=>"inert" - "sulphur"=>"yellow" - "iron"=>"magnetic" - "zebra"=>"striped" - "star"=>"brilliant" - "apple"=>"tasty" - "ruby"=>"red" - "dice"=>"random" - "coffee"=>"stimulating" - "book"=>"interesting" The list, sorted by name: - "apple"=>"tasty" - "book"=>"interesting" - "coffee"=>"stimulating" - "dice"=>"random" - "gold"=>"shiny" - "iron"=>"magnetic" - "neon"=>"inert" - "ruby"=>"red" - "star"=>"brilliant" - "sulphur"=>"yellow" - "zebra"=>"striped" The list, sorted by value: - "star"=>"brilliant" - "neon"=>"inert" - "book"=>"interesting" - "iron"=>"magnetic" - "dice"=>"random" - "ruby"=>"red" - "gold"=>"shiny" - "coffee"=>"stimulating" - "zebra"=>"striped" - "apple"=>"tasty" - "sulphur"=>"yellow"
Kotlin
// version 1.1
data class Employee(val name: String, var category: String) : Comparable<Employee> {
override fun compareTo(other: Employee) = this.name.compareTo(other.name)
}
fun main(args: Array<String>) {
val employees = arrayOf(
Employee("David", "Manager"),
Employee("Alice", "Sales"),
Employee("Joanna", "Director"),
Employee("Henry", "Admin"),
Employee("Tim", "Sales"),
Employee("Juan", "Admin")
)
employees.sort()
for ((name, category) in employees) println("${name.padEnd(6)} : $category")
}
- Output:
Alice : Sales David : Manager Henry : Admin Joanna : Director Juan : Admin Tim : Sales
Lambdatalk
{def H.sort
{def H.sort.i
{lambda {:f :x :a}
{if {A.empty? :a}
then {A.new :x}
else {if {:f :x {A.first :a}}
then {A.addfirst! :x :a}
else {A.addfirst! {A.first :a} {H.sort.i :f :x {A.rest :a}}} }}}}
{def H.sort.r
{lambda {:f :a1 :a2}
{if {A.empty? :a1}
then :a2
else {H.sort.r :f {A.rest :a1} {H.sort.i :f {A.first :a1} :a2}} }}}
{lambda {:f :a}
{H.sort.r :f :a {A.new}} }}
-> H.sort
{def H.display
{lambda {:h}
{table
{tr {S.map {{lambda {:h :i} {td {car {A.get :i :h}}}} :h}
{S.serie 0 {- {A.length :h} 1}}}}
{tr {S.map {{lambda {:h :i} {td {cdr {A.get :i :h}}}} :h}
{S.serie 0 {- {A.length :h} 1}}}}
}}}
-> H.display
1) an array of pairs:
{def H {A.new {cons Joe 5531}
{cons Adam 2341}
{cons Bernie 122}
{cons Walter 1234}
{cons David 19}}}
-> H
2) display sorted by names:
{H.display
{H.sort {lambda {:a :b} {< {lexicographic {car :a} {car :b}} 0}} {H}}}
->
Adam Bernie David Joe Walter
2341 122 19 5531 1234
3) display sorted by values:
{H.display
{H.sort {lambda {:a :b} {< {cdr :a} {cdr :b}}} {H}}}
->
David Bernie Walter Adam Joe
19 122 1234 2341 5531
Liberty BASIC
NB LB sorts in a non standard order. See http://libertybasicbugs.wikispaces.com/Comparison+of+characters+and+strings+is+not+ASCII+based
The method used here to simulate a compound structure can only hold pairs of terms, since LB arrays ar 1D or 2D. More complicated associated arrays could be stored in delimiter-separated string arrays.
N =20
dim IntArray$( N, 2)
print "Original order"
for i =1 to N
name$ =mid$( "SortArrayOfCompositeStructures", int( 25 *rnd( 1)), 1 +int( 4 *rnd( 1)))
IntArray$( i, 1) =name$
print name$,
t$ =str$( int( 1000 *rnd( 1)))
IntArray$( i, 2) =t$
print t$
next i
sort IntArray$(), 1, N, 1
print "Sorted by name" ' ( we specified column 1)
for i =1 to N
print IntArray$( i, 1), IntArray$( i, 2)
next i
Lua
function sorting( a, b )
return a[1] < b[1]
end
tab = { {"C++", 1979}, {"Ada", 1983}, {"Ruby", 1995}, {"Eiffel", 1985} }
table.sort( tab, sorting )
for _, v in ipairs( tab ) do
print( unpack(v) )
end
M2000 Interpreter
Checkit do exactly task need: make pairs as groups of name and value_ (note _ used because value used for other purpose in a group definition), make a Quick group from class Quick, pass a new lambda for comparing items, and pass array with objects to sort in quicksort function of Quick group. Keys no need to be unique.
Checkit2 make an inventory with keys and values, then sort them (internal use Quicksort, and keys must be unique)
Checkit3 same as CheckIt3 except values are groups, which now have only a x as value, but we can add more.
Module CheckIt {
Flush ' empty stack of values
Class Quick {
Private:
partition=lambda-> {
Read &A(), p, r : i = p-1 : x=A(r)
For j=p to r-1 {If .LE(A(j), x) Then i++:Swap A(i),A(j)
} : Swap A(i+1), A(r) : Push i+2, i
}
Public:
LE=Lambda->Number<=Number
Module ForStrings {
.partition<=lambda-> {
Read &a$(), p, r : i = p-1 : x$=a$(r)
For j=p to r-1 {If a$(j)<= x$ Then i++:Swap a$(i),a$(j)
} : Swap a$(i+1), a$(r) : Push i+2, i
}
}
Function quicksort {
Read ref$
{
loop : If Stackitem() >= Stackitem(2) Then Drop 2 : if empty then {Break} else continue
over 2,2 : call .partition(ref$) :shift 3
}
}
}
Quick=Quick()
Quick.LE=lambda (a, b)->{
=a.name$<=b.name$
}
Data "Joe", 5531
Data "Adam", 2341
Data "Bernie", 122
Data "Walter", 1234
Data "David", 19
Class pair {
name$
value_
}
Document Doc$={Unsorted Pairs:
}
Dim A(1 to 5)=pair()
For i=1 to 5 {
For A(i) {
Read .name$, .value_
Doc$=Format$("{0}, {1}", .name$, .value_)+{
}
}
}
Call Quick.quicksort(&A(),1, 5)
Doc$={
Sorted Pairs
}
k=Each(A())
While k {
getone=array(k)
For getone {
Doc$=Format$("{0}, {1}", .name$, .value_)+{
}
}
}
Report Doc$
Clipboard Doc$
}
Checkit
module Checkit2 {
Inventory Alfa="Joe":=5531, "Adam":=2341, "Bernie":=122
Append Alfa, "Walter":=1234, "David":=19
Sort Alfa
k=Each(Alfa)
While k {
Print eval$(Alfa, k^), Eval(k)
}
}
Checkit2
module Checkit3 {
class any {
x
class:
Module any (.x) {}
}
Inventory Alfa="Joe":=any(5531), "Adam":=any(2341), "Bernie":=any(122)
Append Alfa, "Walter":=any(1234), "David":=any(19)
Sort Alfa
k=Each(Alfa)
While k {
\\ k^ is the index number by k cursor
\\ Alfa("joe") return object
\\ Alfa(0!) return first element object
\\ Alfa(k^!) return (k^) objext
Print eval$(Alfa, k^), Alfa(k^!).x
}
}
Checkit3
- Output:
From Checkit (checkit2 and checkit3 show exact sorted inventories)
Unsorted Pairs: Joe, 5531 Adam, 2341 Bernie, 122 Walter, 1234 David, 19 Sorted Pairs Adam, 2341 Bernie, 122 David, 19 Joe, 5531 Walter, 1234
Mathematica /Wolfram Language
events = {{"2009-12-25", "Christmas Day"}, {"2009-04-22",
"Earth Day"}, {"2009-09-07", "Labor Day"}, {"2009-07-04",
"Independence Day"}, {"2009-10-31", "Halloween"}, {"2009-05-25",
"Memorial Day"}, {"2009-03-14", "PI Day"}, {"2009-01-01",
"New Year's Day"}, {"2009-12-31",
"New Year's Eve"}, {"2009-11-26", "Thanksgiving"}, {"2009-02-14",
"St. Valentine's Day"}, {"2009-03-17",
"St. Patrick's Day"}, {"2009-01-19",
"Martin Luther King Day"}, {"2009-02-16", "President's Day"}};
date = 1;
name = 2;
SortBy[events, #[[name]] &] // Grid
SortBy[events, #[[date]] &] // Grid
gives back:
2009-12-25 Christmas Day
2009-04-22 Earth Day
2009-10-31 Halloween
2009-07-04 Independence Day
2009-09-07 Labor Day
2009-01-19 Martin Luther King Day
2009-05-25 Memorial Day
2009-01-01 New Year's Day
2009-12-31 New Year's Eve
2009-03-14 PI Day
2009-02-16 President's Day
2009-03-17 St. Patrick's Day
2009-02-14 St. Valentine's Day
2009-11-26 Thanksgiving
2009-01-01 New Year's Day
2009-01-19 Martin Luther King Day
2009-02-14 St. Valentine's Day
2009-02-16 President's Day
2009-03-14 PI Day
2009-03-17 St. Patrick's Day
2009-04-22 Earth Day
2009-05-25 Memorial Day
2009-07-04 Independence Day
2009-09-07 Labor Day
2009-10-31 Halloween
2009-11-26 Thanksgiving
2009-12-25 Christmas Day
2009-12-31 New Year's Eve
MAXScript
fn keyCmp comp1 comp2 =
(
case of
(
(comp1[1] > comp2[1]): 1
(comp1[1] < comp2[1]): -1
default: 0
)
)
people = #(#("joe", 39), #("dave", 37), #("bob", 42))
qsort people keyCmp
print people
NetRexx
/* NetRexx */
options replace format comments java crossref symbols nobinary
-- =============================================================================
class RSortCompsiteStructure public
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method main(args = String[]) public static
places = [ -
PairBean('London', 'UK'), PairBean('New York', 'US') -
, PairBean('Boston', 'US'), PairBean('Washington', 'US') -
, PairBean('Washington', 'UK'), PairBean("Birmingham", 'US') -
, PairBean("Birmingham", 'UK'), PairBean("Boston", 'UK') -
]
say displayArray(places)
Arrays.sort(places, PairComparator())
say displayArray(places)
return
method displayArray(harry = PairBean[]) constant
disp = ''
loop elmt over harry
disp = disp','elmt
end elmt
return '['disp.substr(2)']' -- trim leading comma
-- =============================================================================
class RSortCompsiteStructure.PairBean
properties indirect
name
value
method PairBean(name_, value_) public
setName(name_)
setValue(value_)
return
method toString() public returns String
return '('getName()','getValue()')'
-- =============================================================================
class RSortCompsiteStructure.PairComparator implements Comparator
method compare(lft = Object, rgt = Object) public binary returns int
cRes = int
if lft <= RSortCompsiteStructure.PairBean, rgt <= RSortCompsiteStructure.PairBean then do
lName = String (RSortCompsiteStructure.PairBean lft).getName()
rName = String (RSortCompsiteStructure.PairBean rgt).getName()
cRes = lName.compareTo(rName)
if cRes == 0 then do
lVal = String (RSortCompsiteStructure.PairBean lft).getValue()
rVal = String (RSortCompsiteStructure.PairBean rgt).getValue()
cRes = lVal.compareTo(rVal)
end
end
else signal IllegalArgumentException('Arguments must be of type PairBean')
return cRes
Output:
[(London,UK),(New York,US),(Boston,US),(Washington,US),(Washington,UK),(Birmingham,US),(Birmingham,UK),(Boston,UK)] [(Birmingham,UK),(Birmingham,US),(Boston,UK),(Boston,US),(London,UK),(New York,US),(Washington,UK),(Washington,US)]
Nim
import algorithm, sugar
var people = @{"joe": 120, "foo": 31, "bar": 51}
sort(people, (x,y) => cmp(x[0], y[0]))
echo people
- Output:
@[("bar", 51), ("foo", 31), ("joe", 120)]
Objeck
use Collection;
class Entry implements Compare {
@name : String;
@value : Float;
New(name : String, value : Float) {
@name := name;
@value := value;
}
method : public : Compare(rhs : Compare) ~ Int {
return @name->Compare(rhs->As(Entry)->GetName());
}
method : public : GetName() ~ String {
return @name;
}
method : public : HashID() ~ Int {
return @name->HashID();
}
method : public : ToString() ~ String {
return "name={$@name}, value={$@value}";
}
}
class Sorter {
function : Main(args : String[]) ~ Nil {
entries := CompareVector->New();
entries->AddBack(Entry->New("Krypton", 83.798));
entries->AddBack(Entry->New("Beryllium", 9.012182));
entries->AddBack(Entry->New("Silicon", 28.0855));
entries->AddBack(Entry->New("Cobalt", 58.933195));
entries->AddBack(Entry->New("Selenium", 78.96));
entries->AddBack(Entry->New("Germanium", 72.64));
entries->Sort();
each(i : entries) {
entries->Get(i)->As(Entry)->ToString()->PrintLine();
};
}
}
name=Beryllium, value=9.12 name=Cobalt, value=58.934 name=Germanium, value=72.640 name=Krypton, value=83.798 name=Selenium, value=78.960 name=Silicon, value=28.85
Objective-C
@interface Pair : NSObject {
NSString *name;
NSString *value;
}
+(instancetype)pairWithName:(NSString *)n value:(NSString *)v;
-(instancetype)initWithName:(NSString *)n value:(NSString *)v;
-(NSString *)name;
-(NSString *)value;
@end
@implementation Pair
+(instancetype)pairWithName:(NSString *)n value:(NSString *)v {
return [[self alloc] initWithName:n value:v];
}
-(instancetype)initWithName:(NSString *)n value:(NSString *)v {
if ((self = [super init])) {
name = n;
value = v;
}
return self;
}
-(NSString *)name { return name; }
-(NSString *)value { return value; }
-(NSString *)description {
return [NSString stringWithFormat:@"< %@ -> %@ >", name, value];
}
@end
int main() {
@autoreleasepool {
NSArray *pairs = @[
[Pair pairWithName:@"06-07" value:@"Ducks"],
[Pair pairWithName:@"00-01" value:@"Avalanche"],
[Pair pairWithName:@"02-03" value:@"Devils"],
[Pair pairWithName:@"01-02" value:@"Red Wings"],
[Pair pairWithName:@"03-04" value:@"Lightning"],
[Pair pairWithName:@"04-05" value:@"lockout"],
[Pair pairWithName:@"05-06" value:@"Hurricanes"],
[Pair pairWithName:@"99-00" value:@"Devils"],
[Pair pairWithName:@"07-08" value:@"Red Wings"],
[Pair pairWithName:@"08-09" value:@"Penguins"]];
// optional 3rd arg: you can also specify a selector to compare the keys
NSSortDescriptor *sd = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
// it takes an array of sort descriptors, and it will be ordered by the
// first one, then if it's a tie by the second one, etc.
NSArray *sorted = [pairs sortedArrayUsingDescriptors:@[sd]];
NSLog(@"%@", sorted);
}
return 0;
}
OCaml
# let people = [("Joe", 12); ("Bob", 8); ("Alice", 9); ("Harry", 2)];;
val people : (string * int) list =
[("Joe", 12); ("Bob", 8); ("Alice", 9); ("Harry", 2)]
# let sortedPeopleByVal = List.sort (fun (_, v1) (_, v2) -> compare v1 v2) people;;
val sortedPeopleByVal : (string * int) list =
[("Harry", 2); ("Bob", 8); ("Alice", 9); ("Joe", 12)]
Oforth
[["Joe",5531], ["Adam",2341], ["Bernie",122], ["David",19]] sortBy(#first) println
- Output:
[[Adam, 2341], [Bernie, 122], [David, 19], [Joe, 5531]]
Ol
(import (scheme char))
(define (comp a b)
(string-ci<? (a 'name #f) (b 'name #f)))
(for-each print
(sort comp (list
{ 'name "David"
'value "Manager" }
{ 'name "Alice"
'value "Sales" }
{ 'name "Joanna"
'value "Director" }
{ 'name "Henry"
'value "Admin" }
{ 'name "Tim"
'value "Sales" }
{ 'name "Juan"
'value "Admin" })))
- Output:
#ff((name . Alice) (value . Sales)) #ff((name . David) (value . Manager)) #ff((name . Henry) (value . Admin)) #ff((name . Joanna) (value . Director)) #ff((name . Juan) (value . Admin)) #ff((name . Tim) (value . Sales))
ooRexx
a = .array~new
a~append(.pair~new("06-07", "Ducks"))
a~append(.pair~new("00-01", "Avalanche"))
a~append(.pair~new("02-03", "Devils"))
a~append(.pair~new("01-02", "Red Wings"))
a~append(.pair~new("03-04", "Lightning"))
a~append(.pair~new("04-05", "lockout"))
a~append(.pair~new("05-06", "Hurricanes"))
a~append(.pair~new("99-00", "Devils"))
a~append(.pair~new("07-08", "Red Wings"))
a~append(.pair~new("08-09", "Penguins"))
b = a~copy -- make a copy before sorting
b~sort
say "Sorted using direct comparison"
do pair over b
say pair
end
c = a~copy
-- this uses a custom comparator instead
c~sortWith(.paircomparator~new)
say
say "Sorted using a comparator (inverted)"
do pair over c
say pair
end
-- a name/value mapping class that directly support the sort comparisons
::class pair inherit comparable
::method init
expose name value
use strict arg name, value
::attribute name
::attribute value
::method string
expose name value
return name "=" value
-- the compareto method is a requirement brought in
-- by the
::method compareto
expose name
use strict arg other
return name~compareto(other~name)
-- a comparator that shows an alternate way of sorting
::class pairComparator subclass comparator
::method compare
use strict arg left, right
-- perform the comparison on the names
return -left~name~compareTo(right~name)
Output:
Sorted using direct comparison 00-01 = Avalanche 01-02 = Red Wings 02-03 = Devils 03-04 = Lightning 04-05 = lockout 05-06 = Hurricanes 06-07 = Ducks 07-08 = Red Wings 08-09 = Penguins 99-00 = Devils Sorted using a comparator (inverted) 99-00 = Devils 08-09 = Penguins 07-08 = Red Wings 06-07 = Ducks 05-06 = Hurricanes 04-05 = lockout 03-04 = Lightning 02-03 = Devils 01-02 = Red Wings 00-01 = Avalanche
Oz
declare
People = [person(name:joe value:3)
person(name:bill value:4)
person(name:alice value:20)
person(name:harry value:3)]
SortedPeople = {Sort People
fun {$ P1 P2}
P1.name < P2.name
end
}
in
{ForAll SortedPeople Show}
PARI/GP
The flag "2" means that lexicographic sorting is to be used; the "1" means that the array is to be sorted using the first element of each constituent vector.
vecsort([["name", "value"],["name2", "value2"]], 1, 2)
Pascal
mergesort example sorts an array of record http://rosettacode.org/wiki/Sorting_algorithms/Merge_sort#improvement
PascalABC.NET
type
Pair = auto class
Name,Value: string;
end;
begin
var a: array of Pair := (new Pair('ZZZ','333'),new Pair('XXX','222'),new Pair('YYY','111'));
a.OrderBy(p -> p.Name).Println;
a.OrderBy(p -> p.Value).Println;
end.
- Output:
(XXX,222) (YYY,111) (ZZZ,333) (YYY,111) (XXX,222) (ZZZ,333)
Perl
Sort by name using cmp to compare strings:
@people = (['joe', 120], ['foo', 31], ['bar', 51]);
@people = sort { $a->[0] cmp $b->[0] } @people;
Sort by number using <=> to compare numbers:
@people = (['joe', 120], ['foo', 31], ['bar', 51]);
@people = sort { $a->[1] <=> $b->[1] } @people;
Phix
The standard sort compares the first element, then 2nd, 3rd, etc. A custom_sort or sort_columns can be used to sort by other elements.
Elements can be any mix of types, with atoms (ie ints/floats) deemed less than sequences/strings.
sequence s = {{"grass","green"},{"snow","white"},{"sky","blue"},{"cherry","red"},{0,1.2},{3.4,-1}} ?sort(s) function compare_col2(sequence a, b) return compare(a[2],b[2]) end function ?custom_sort(compare_col2,s) ?sort_columns(s,{2}) -- 0.8.0+, same result as above w/o needing an explicit comparison routine
- Output:
{{0,1.2},{3.4,-1},{"cherry","red"},{"grass","green"},{"sky","blue"},{"snow","white"}} {{3.4,-1},{0,1.2},{"sky","blue"},{"grass","green"},{"cherry","red"},{"snow","white"}} {{3.4,-1},{0,1.2},{"sky","blue"},{"grass","green"},{"cherry","red"},{"snow","white"}}
Phixmonti
include ..\Utilitys.pmt
def minverse
reverse
enddef
getid minverse var f
( ( "grass" "green" ) ( "snow" "white" ) ( "sky" "blue" ) ( "cherry" "red" ) ( 0 1.2 ) ( 3.4 -1 ) )
dup
sort print nl
/# sorted by second component #/
f map sort f map print
PicoLisp
By default, the sort function in PicoLisp returns an ascending list (of any type)
: (sort '(("def" 456) ("abc" 789) ("ghi" 123)))
-> (("abc" 789) ("def" 456) ("ghi" 123))
To sort by a certain sub-element, the function by can be used. For example, to sort by the first element
: (by car sort '(("def" 456) ("abc" 789) ("ghi" 123)))
-> (("abc" 789) ("def" 456) ("ghi" 123))
or by the second element
: (by cadr sort '(("def" 456) ("abc" 789) ("ghi" 123)))
-> (("ghi" 123) ("def" 456) ("abc" 789))
PowerShell
$list = @{
"def" = "one"
"abc" = "two"
"jkl" = "three"
"abcdef" = "four"
"ghi" = "five"
"ghijkl" = "six"
}
$list.GetEnumerator() | sort {-($PSItem.Name).length}, Name
Output:
Name Value ---- ----- abcdef four ghijkl six abc two def one ghi five jkl three
PureBasic
PureBasic natively supports sorting of structured data with;
- SortStructuredArray()
- SortStructuredList()
The on-line documentations gives a more complete picture.
Example
Structure MyPair ; Define a structured data type
Name$
Value.i
EndStructure
Dim People.MyPair(2) ; Allocate some elements
People(0)\Name$ = "John" ; Start filling them in
People(0)\Value = 100
People(1)\Name$ = "Emma"
People(1)\Value = 200
People(2)\Name$ = "Johnny"
People(2)\Value = 175
If OpenConsole()
Define i
; Sort ascending by name
SortStructuredArray(People(), #PB_Sort_Ascending, OffsetOf(MyPair\Name$), #PB_Sort_String)
PrintN(#CRLF$+"Sorted ascending by name.")
For i=0 To 2
PrintN(People(i)\Name$+" - Value: "+Str(People(i)\Value))
Next
; Sort descending by value
SortStructuredArray(People(), #PB_Sort_Descending, OffsetOf(MyPair\Value), #PB_Sort_Integer)
PrintN(#CRLF$+"Sorted descending by value.")
For i=0 To 2
PrintN(People(i)\Name$+" - Value: "+Str(People(i)\Value))
Next
; Wait for user...
PrintN(#CRLF$+"Press ENTER to exit"):Input()
EndIf
Outputs
Sorted ascending by name. Emma - Value: 200 John - Value: 100 Johnny - Value: 175 Sorted descending by value. Emma - Value: 200 Johnny - Value: 175 John - Value: 100
Python
Recent versions of Python provide the sorted() built-in that works on any iterable.
people = [('joe', 120), ('foo', 31), ('bar', 51)]
sorted(people)
Which leaves people
with the value:
[('bar', 51), ('foo', 31), ('joe', 120)]
The most Pythonic (and fastest) version is to use itemgetter together with the key parameter to sort
resp. sorted
to perform the Decorate-sort-undecorate pattern:
from operator import itemgetter
people = [(120, 'joe'), (31, 'foo'), (51, 'bar')]
people.sort(key=itemgetter(1))
Which leaves people
with the value:
[(51, 'bar'), (31, 'foo'), (120, 'joe')]
R
In R, vectors can have names associated with any of its elements. The data is taken from the Common Lisp example.
sortbyname <- function(x, ...) x[order(names(x), ...)]
x <- c(texas=68.9, ohio=87.8, california=76.2, "new york"=88.2)
sortbyname(x)
california new york ohio texas 76.2 88.2 87.8 68.9
sortbyname(x, decreasing=TRUE)
texas ohio new york california 68.9 87.8 88.2 76.2
Racket
#lang racket
(define data '([Joe 5531] [Adam 2341] [Bernie 122] [Walter 1234] [David 19]))
(sort data < #:key cadr)
;; --> '((David 19) (Bernie 122) (Walter 1234) (Adam 2341) (Joe 5531))
;; Demonstrating a "key" that is not just a direct element
(sort data string<? #:key (compose1 symbol->string car))
;; --> '((Adam 2341) (Bernie 122) (David 19) (Joe 5531) (Walter 1234))
Raku
(formerly Perl 6)
my class Employee {
has Str $.name;
has Rat $.wage;
}
my $boss = Employee.new( name => "Frank Myers" , wage => 6755.85 );
my $driver = Employee.new( name => "Aaron Fast" , wage => 2530.40 );
my $worker = Employee.new( name => "John Dude" , wage => 2200.00 );
my $salesman = Employee.new( name => "Frank Mileeater" , wage => 4590.12 );
my @team = $boss, $driver, $worker, $salesman;
my @orderedByName = @team.sort( *.name )».name;
my @orderedByWage = @team.sort( *.wage )».name;
say "Team ordered by name (ascending order):";
say @orderedByName.join(' ');
say "Team ordered by wage (ascending order):";
say @orderedByWage.join(' ');
this produces the following output:
Team ordered by name (ascending order): Aaron Fast Frank Mileeater Frank Myers John Dude Team ordered by wage (ascending order): John Dude Aaron Fast Frank Mileeater Frank Myers
Note that when the sort receives a unary function, it automatically generates an appropriate comparison function based on the type of the data.
REXX
General remarks
Both Regina and Classic ooRexx have standard no sorting facilities built-in. However, we have Patrick McPhee's library Regutil for Regina offering SysStemSort (sort 1 stem) and RegMultiStemSort (sort 1 key stem, syncing 1 to n data stems). And ooRexx has RexxUtil offering SysStemSort (sort 1 stem). Both utilities support only a string sort and require you to build a concatenated key (fixed columns for key values) in case of multiple sort arguments (as in this task). And, by the way, their parameters are not compatible.
But we want our solutions in this category to run at least under both Regina and ooRexx. Thus a solution must be found for the limitations around stems, i.e. not be able to pass a stem to a procedure nor return one.
Version 1
This version sorts the structure by color; as entered (built), the structure is ordered by value (percent).
The name x. is used for the stem, with associated pairs x.1.color, x.2. color etc and x.1.value, x.2.value etc. Stem x. is exposed to all procedures needing it.
/*REXX program sorts an array of composite structures */
/* (which has two classes of data). */
x.=0 /*number elements in structure (so far)*/
Call add 'tan' , 0 /*tan peanut M&M's are 0% of total*/
Call add 'orange',10 /*orange " " " 10% " " */
Call add 'yellow',20 /*yellow " " " 20% " " */
Call add 'green' ,20 /*green " " " 20% " " */
Call add 'red' ,20 /*red " " " 20% " " */
Call add 'brown' ,30 /*brown " " " 30% " " */
Call show 'before sort'
Say copies('¦', 70)
Call xSort
call show ' after sort'
Exit /*stick a fork in it, we're all done. */
/*--------------------------------------------------------------------*/
add: Procedure Expose x.
z=x.0+1 /* bump the number of structure entry */
x.z.color=arg(1)
x.z.pc=arg(2) /* construct an entry of the structure */
x.0=z
Return
/*--------------------------------------------------------------------*/
show: Procedure Expose x.
Do i=1 To x.0
/* display what name value. */
Say right(arg(1),30) right(x.i.color,9) right(x.i.pc,4)'%'
End
Return
/*--------------------------------------------------------------------*/
xsort: Procedure Expose x.
h=x.0
Do While h>1
h=h%2
Do i=1 For x.0-h
j=i
k=h+i
Do While x.k.color<x.j.color
_=x.j.color /* swap elements. */
x.j.color=x.k.color
x.k.color=_
_=x.j.pc
x.j.pc=x.k.pc
x.k.pc=_
If h>=j Then
Leave
j=j-h
k=k-h
End
End
End
Return
output when using the (internal) default inputs:
before sort tan 0% before sort orange 10% before sort yellow 20% before sort green 20% before sort red 20% before sort brown 30% ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ after sort brown 30% after sort green 20% after sort orange 10% after sort red 20% after sort tan 0% after sort yellow 20%
Realistic example
I asked ChatGPT (nice tool...): 'Give me a list of all US states, and per state the 3 cities with the highest population, in CSV format'. The result was neatly sorted, but for this example I shuffled the list. It shows as
California,Los Angeles,3884307 Utah,Salt Lake City,199927 New Mexico,Las Cruces,111385 California,San Diego,1423851 California,San Jose,1021795 Missouri,Saint Louis,302838 New Mexico,Rio Rancho,101008 Michigan,Grand Rapids,197416 Nevada,Reno,260068 Idaho,Nampa,100200 Arizona,Mesa,508958 Oregon,Eugene,176654 Maine,Bangor,32178 Texas,Houston,2325502 Utah,Provo,116288 Alaska,Juneau,31275 Texas,Dallas,1335795 Hawaii,Kailua,37713 Florida,Tampa,392890 Florida,Miami,478251 Idaho,Boise,236310 Oregon,Salem,168916 Hawaii,Hilo,45784 Ohio,Columbus,905748 Iowa,Davenport,102320 Idaho,Meridian,117322 Alabama,Mobile,195111 Maine,Lewiston,36277 Ohio,Cleveland,372624 Delaware,Dover,38202 Kansas,Wichita,391731 Oklahoma,Tulsa,391906 Nebraska,Omaha,486051 Arizona,Tucson,548073 Wyoming,Casper,58500 Maine,Portland,67506 South Carolina,Charleston,150227 North Carolina,Charlotte,874579 South Carolina,Columbia,137318 North Carolina,Greensboro,306614 South Carolina,North Charleston,118974 North Carolina,Raleigh,474069 Massachusetts,Boston,645966 Vermont,South Burlington,19480 West Virginia,Charleston,48387 Kansas,Kansas City,152960 New Hampshire,Concord,42629 Montana,Great Falls,59488 West Virginia,Huntington,45531 New Hampshire,Manchester,115644 New Hampshire,Nashua,88341 Louisiana,New Orleans,384320 West Virginia,Parkersburg,30701 Arkansas,Fort Smith,87674 Massachusetts,Springfield,153606 Massachusetts,Worcester,185885 Illinois,Aurora,197757 Georgia,Augusta,202679 Colorado,Aurora,361710 Georgia,Atlanta,498715 Colorado,Colorado Springs,457568 Connecticut,Stamford,129775 South Dakota,Rapid City,74388 Indiana,Indianapolis,855164 North Dakota,Fargo,124662 New Jersey,Newark,281054 Rhode Island,Warwick,81481 Nevada,Las Vegas,641676 Wisconsin,Milwaukee,592025 Indiana,Fort Wayne,264488 South Dakota,Aberdeen,27653 Mississippi,Jackson,172638 Kansas,Overland Park,190886 Vermont,Rutland,15942 Oregon,Portland,632309 Arkansas,Little Rock,202591 Wyoming,Laramie,32311 Minnesota,Minneapolis,429606 Maryland,Gaithersburg,67404 New Jersey,Paterson,146199 Minnesota,Rochester,223873 Utah,West Valley City,136574 Alaska,Anchorage,291538 Missouri,Springfield,165794 Alabama,Birmingham,200733 Illinois,Chicago,2716000 Montana,Billings,109577 Kentucky,Lexington,323780 Vermont,Burlington,42304 Pennsylvania,Philadelphia,1567442 Tennessee,Memphis,660388 Ohio,Cincinnati,298165 Connecticut,Bridgeport,144399 Iowa,Cedar Rapids,132228 Indiana,Evansville,119943 South Dakota,Sioux Falls,186502 North Dakota,Bismarck,74151 Michigan,Detroit,672662 Pennsylvania,Pittsburgh,305704 Delaware,Newark,34544 Washington,Spokane,230707 Alaska,Fairbanks,31516 Montana,Missoula,68220 Mississippi,Gulfport,71375 Virginia,Norfolk,244835 Pennsylvania,Allentown,118577 Nebraska,Lincoln,280849 New York,Buffalo,256480 Alabama,Montgomery,199518 Maryland,Baltimore,622104 Wisconsin,Green Bay,107395 Louisiana,Baton Rouge,227715 Oklahoma,Norman,124880 Michigan,Warren,134056 Wyoming,Cheyenne,64235 Kentucky,Bowling Green,67226 Delaware,Wilmington,70973 Virginia,Virginia Beach,450189 Texas,San Antonio,1532233 Florida,Jacksonville,949611 Oklahoma,Oklahoma City,649021 Washington,Tacoma,213418 Nevada,Henderson,310390 New York,New York,8537673 Virginia,Chesapeake,247036 Colorado,Denver,716492 North Dakota,Grand Forks,55231 Rhode Island,Cranston,80566 Maryland,Frederick,71726 Rhode Island,Providence,179207 Missouri,Kansas City,508090 Iowa,Des Moines,214237 New Jersey,Jersey City,280579 Wisconsin,Madison,258054 New York,Rochester,208046 Minnesota,Saint Paul,308096 Arkansas,Fayetteville,74880 Washington,Seattle,787995 Hawaii,Honolulu,337256 New Mexico,Albuquerque,559277 Georgia,Columbus,206922 Mississippi,Southaven,55200 Louisiana,Shreveport,194920 Illinois,Naperville,147122 Tennessee,Knoxville,190740 Kentucky,Louisville,621349 Tennessee,Nashville,634464 Nebraska,Bellevue,272117 Connecticut,New Haven,130322 Arizona,Phoenix,1680992
A nice table to play with: duplicates in the first entry and numeric values in the last entry. I stored it in States.txt, and will use it in subsequential examples.
Now, let's use a 'database' approach, just like in the entry Sort_an_array_of_composite_structures#SQL
Above data forms a table, say states, having three columns state (char), city (char) and pop (int). So let's use a stem with head 'states.' and tails 'state.x', 'city.x' and 'pop.x', x = row number. Exposing 'states.' to each procedures serves as providing a table to the procedure. And let states.0 hold the number of rows. This naming convention closely mimics the fully qualified names for tables and columns in SQL, and shows clearly the relation between the tails as belonging to the head 'states.'.
By the way, this way of naming and storing is essentially the same as in Version 1, nothing new here.
Libraries
REXX does not have an 'include' facility nor 'arbitrary precision' mathematical functions out of the
box. In previous REXX entries it was custom the have all needed routines and procedures copied into
the program. Newer entries redirect to
Libraries and
Pre processor and Include clause.
At the end of each entry you'll find several 'include' clauses, showing the libraries that the program
needs (cf '#include', 'import', 'uses' or '::requires').
The use of this tool is highly recommended. But you may always copy the source code into your program
and do the text changes yourself, i.e. change all '[label]' to 'some_name' etc.
Versions 2 and 3
Now, using the data structure
- states. (table)
- states.0 = n (number of rows)
- states.state.x (column state)
- states.city.x (column city)
- states.pop.x (column population)
we arrive at following program and procedures.
Program, creating a table and invoking several sorts on different columns, using two types of (quick)sorting procedure.
Main:
call Create
call Show 'Not ordered'
call SortStateCity
call Show 'By state and city'
call SortPopCityN
call Show 'By pop (numeric desc) and city'
table = 'states.'; keys = 'pop. state.'; data = 'city.'
call SortPopCityS table,keys,data
call Show 'By pop (string) and city'
table = 'states.'; keys = 'city. state.'; data = 'pop.'
call SortCityState table,keys,data
call Show 'By city and state'
return
Create:
states = 'States.txt'
call Stream states,'c','open read'
states. = ''; n = 0
do while lines(states) > 0
record = linein(states)
parse var record rstate','rcity','rpop
n = n+1; states.state.n = rstate; states.city.n = rcity; states.pop.n = rpop
end
call Stream states,'c','close'
states.0 = n
return
Show:
procedure expose states.
arg header
say center(header,53)
say right('row',3) left('state',20) left('city',20) right('pop',7)
do n = 1 to states.0
say right(n,3) left(states.state.n,20) left(states.city.n,20) right(states.pop.n,7)
end
say
return
include Quicksort21 [label]=SortStateCity [table]=states. [key1]=state. [key2]=city. [data1]=pop.
include Quicksort21 [label]=SortPopCityN [table]=states. [key1]=pop. [key2]=city. [data1]=state. [lt]=> [gt]=<
include Quicksort [label]=SortCityState
include Quicksort [label]=SortPopCityS [lt]=<< [gt]=>>
Quicksort, optimized for exactly 2 key columns and 1 data column.
default [label]=Quicksort21 [table]=table. [key1]=key1. [key2]=key2. [data1]=data1. [lt]=< [eq]== [gt]=>
-- Sorting procedure - Build 20240806
-- (C) Paul van den Eertwegh 2024
[label]:
-- Sort a stem on 2 key columns, syncing 1 data column
procedure expose [table]
-- Sort
n = [table]0; s = 1; sl.1 = 1; sr.1 = n
do until s = 0
l = sl.s; r = sr.s; s = s-1
do until l >= r
-- Up to 19 rows selection sort is faster
if r-l < 20 then do
do i = l+1 to r
a = [table][key1]i
b = [table][key2]i
c = [table][data1]i
do j = i-1 by -1 to l
if [table][key1]j [lt] a then
leave
if [table][key1]j [eq] a then
if [table][key2]j [lt]= b then
leave
k = j+1
[table][key1]k = [table][key1]j
[table][key2]k = [table][key2]j
[table][data1]k = [table][data1]j
end
k = j+1
[table][key1]k = a
[table][key2]k = b
[table][data1]k = c
end
if s = 0 then
leave
l = sl.s; r = sr.s; s = s-1
end
else do
-- Find optimized pivot
m = (l+r)%2
if [table][key1]l [gt] [table][key1]m then do
t = [table][key1]l; [table][key1]l = [table][key1]m; [table][key1]m = t
t = [table][key2]l; [table][key2]l = [table][key2]m; [table][key2]m = t
t = [table][data1]l; [table][data1]l = [table][data1]m; [table][data1]m = t
end
else do
if [table][key1]l [eq] [table][key1]m then do
if [table][key2]l [gt] [table][key2]m then do
t = [table][key2]l; [table][key2]l = [table][key2]m; [table][key2]m = t
t = [table][data1]l; [table][data1]l = [table][data1]m; [table][data1]m = t
end
end
end
if [table][key1]l [gt] [table][key1]r then do
t = [table][key1]l; [table][key1]l = [table][key1]r; [table][key1]r = t
t = [table][key2]l; [table][key2]l = [table][key2]r; [table][key2]r = t
t = [table][data1]l; [table][data1]l = [table][data1]r; [table][data1]r = t
end
else do
if [table][key1]l [eq] [table][key1]r then do
if [table][key2]l [gt] [table][key2]r then do
t = [table][key2]l; [table][key2]l = [table][key2]r; [table][key2]r = t
t = [table][data1]l; [table][data1]l = [table][data1]r; [table][data1]r = t
end
end
end
if [table][key1]m [gt] [table][key1]r then do
t = [table][key1]m; [table][key1]m = [table][key1]r; [table][key1]r = t
t = [table][key2]m; [table][key2]m = [table][key2]r; [table][key2]r = t
t = [table][data1]m; [table][data1]m = [table][data1]r; [table][data1]r = t
end
else do
if [table][key1]m [eq] [table][key1]r then do
if [table][key2]m [gt] [table][key2]r then do
t = [table][key2]m; [table][key2]m = [table][key2]r; [table][key2]r = t
t = [table][data1]m; [table][data1]m = [table][data1]r; [table][data1]r = t
end
end
end
-- Rearrange rows in partition
i = l; j = r
a = [table][key1]m
b = [table][key2]m
do until i > j
do i = i
if [table][key1]i [gt] a then
leave
if [table][key1]i [eq] a then
if [table][key2]i [gt]= b then
leave
end
do j = j by -1
if [table][key1]j [lt] a then
leave
if [table][key1]j [eq] a then
if [table][key2]j [lt]= b then
leave
end
if i <= j then do
t = [table][key1]i; [table][key1]i = [table][key1]j; [table][key1]j = t
t = [table][key2]i; [table][key2]i = [table][key2]j; [table][key2]j = t
t = [table][data1]i; [table][data1]i = [table][data1]j; [table][data1]j = t
i = i+1; j = j-1
end
end
-- Next partition
if j-l < r-i then do
if i < r then do
s = s+1; sl.s = i; sr.s = r
end
r = j
end
else do
if l < j then do
s = s+1; sl.s = l; sr.s = j
end
l = i
end
end
end
end
return
Quicksort, able to sort a table on any number of key columns, syncing any number of data columns.
Ugh... Nasty code with all those calls to Value(), but it works. Check the documentation on the Value() function if you are not familiar with it.
default [label]=Quicksort [lt]=< [eq]== [gt]=>
/* Sorting procedure - Build 20240805 */
/* (C) Paul van den Eertwegh 2024 */
[label]:
/* Sort on 1 or more key stems, syncing 0 or more data stems */
procedure expose (table)
arg table,keys,data
/* Collect keys */
kn = words(keys)
do x = 1 to kn
key.x = word(keys,x)
end
/* Collect data */
dn = words(data)
do x = 1 to dn
data.x = word(data,x)
end
/* Sort */
n = value(table||0); s = 1; sl.1 = 1; sr.1 = n
do until s = 0
l = sl.s; r = sr.s; s = s-1
do until l >= r
/* Up to 19 rows selection sort is faster */
if r-l < 20 then do
do i = l+1 to r
do x = 1 to kn
k.x = value(table||key.x||i)
end
do x = 1 to dn
d.x = value(table||data.x||i)
end
do j=i-1 to l by -1
do x = 1 to kn
a = value(table||key.x||j)
if a [gt] k.x then
leave x
if a [eq] k.x then
if x < kn then
iterate x
leave j
end
k = j+1
do x = 1 to kn
t = value(table||key.x||j)
call value table||key.x||k,t
end
do x = 1 to dn
t = value(table||data.x||j)
call value table||data.x||k,t
end
end
k = j+1
do x = 1 to kn
call value table||key.x||k,k.x
end
do x = 1 to dn
call value table||data.x||k,d.x
end
end
if s = 0 then
leave
l = sl.s; r = sr.s; s = s-1
end
else do
/* Find optimized pivot */
m = (l+r)%2
do x = 1 to kn
a = value(table||key.x||l); b = value(table||key.x||m)
if a [gt] b then do
do y = 1 to kn
t = value(table||key.y||l); u = value(table||key.y||m)
call value table||key.y||l,u; call value table||key.y||m,t
end
do y = 1 to dn
t = value(table||data.y||l); u = value(table||data.y||m)
call value table||data.y||l,u; call value table||data.y||m,t
end
leave
end
if a [lt] b then
leave
end
do x = 1 to kn
a = value(table||key.x||l); b = value(table||key.x||r)
if a [gt] b then do
do y = 1 to kn
t = value(table||key.y||l); u = value(table||key.y||r)
call value table||key.y||l,u; call value table||key.y||r,t
end
do y = 1 to dn
t = value(table||data.y||l); u = value(table||data.y||r)
call value table||data.y||l,u; call value table||data.y||r,t
end
leave
end
if a [lt] b then
leave
end
do x = 1 to kn
a = value(table||key.x||m); b = value(table||key.x||r)
if a [gt] b then do
do y = 1 to kn
t = value(table||key.y||m); u = value(table||key.y||r)
call value table||key.y||m,u; call value table||key.y||r,t
end
do y = 1 to dn
t = value(table||data.y||m); u = value(table||data.y||r)
call value table||data.y||m,u; call value table||data.y||r,t
end
leave
end
if a [lt] b then
leave
end
/* Rearrange rows in partition */
i = l; j = r
do x = 1 to kn
p.x = value(table||key.x||m)
end
do until i > j
do i = i
do x = 1 to kn
a = value(table||key.x||i)
if a [lt] p.x then
leave x
if a [eq] p.x then
if x < kn then
iterate x
leave i
end
end
do j = j by -1
do x = 1 to kn
a = value(table||key.x||j)
if a [gt] p.x then
leave x
if a [eq] p.x then
if x < kn then
iterate x
leave j
end
end
if i <= j then do
do x = 1 to kn
t = value(table||key.x||i); u = value(table||key.x||j)
call value table||key.x||i,u; call value table||key.x||j,t
end
do x = 1 to dn
t = value(table||data.x||i); u = value(table||data.x||j)
call value table||data.x||i,u; call value table||data.x||j,t
end
i = i+1; j = j-1
end
end
/* Next partition */
if j-l < r-i then do
if i < r then do
s = s+1; sl.s = i; sr.s = r
end
r = j
end
else do
if l < j then do
s = s+1; sl.s = l; sr.s = j
end
l = i
end
end
end
end
return
You may have noticed the replaceable texts [lt], [eq] and [gt]. These are present in the procedures at strategic points and allows you to control the sort: ascending ([lt]=< and [gt]=>) vs descending ([lt]=> and [gt]=<) and numeric (use < = >) or string (use << == >>). See the rexx documentation about strict comparisons. The include clauses in the first program provide examples.
Running the program yields following output. For the sorted entries only the first 10 rows are shown.
- Output:
NOT ORDERED row state city pop 1 California Los Angeles 3884307 2 Utah Salt Lake City 199927 3 New Mexico Las Cruces 111385 4 California San Diego 1423851 5 California San Jose 1021795 6 Missouri Saint Louis 302838 7 New Mexico Rio Rancho 101008 8 Michigan Grand Rapids 197416 9 Nevada Reno 260068 10 Idaho Nampa 100200 11 Arizona Mesa 508958 12 Oregon Eugene 176654 13 Maine Bangor 32178 14 Texas Houston 2325502 15 Utah Provo 116288 16 Alaska Juneau 31275 17 Texas Dallas 1335795 18 Hawaii Kailua 37713 19 Florida Tampa 392890 20 Florida Miami 478251 21 Idaho Boise 236310 22 Oregon Salem 168916 23 Hawaii Hilo 45784 24 Ohio Columbus 905748 25 Iowa Davenport 102320 26 Idaho Meridian 117322 27 Alabama Mobile 195111 28 Maine Lewiston 36277 29 Ohio Cleveland 372624 30 Delaware Dover 38202 31 Kansas Wichita 391731 32 Oklahoma Tulsa 391906 33 Nebraska Omaha 486051 34 Arizona Tucson 548073 35 Wyoming Casper 58500 36 Maine Portland 67506 37 South Carolina Charleston 150227 38 North Carolina Charlotte 874579 39 South Carolina Columbia 137318 40 North Carolina Greensboro 306614 41 South Carolina North Charleston 118974 42 North Carolina Raleigh 474069 43 Massachusetts Boston 645966 44 Vermont South Burlington 19480 45 West Virginia Charleston 48387 46 Kansas Kansas City 152960 47 New Hampshire Concord 42629 48 Montana Great Falls 59488 49 West Virginia Huntington 45531 50 New Hampshire Manchester 115644 51 New Hampshire Nashua 88341 52 Louisiana New Orleans 384320 53 West Virginia Parkersburg 30701 54 Arkansas Fort Smith 87674 55 Massachusetts Springfield 153606 56 Massachusetts Worcester 185885 57 Illinois Aurora 197757 58 Georgia Augusta 202679 59 Colorado Aurora 361710 60 Georgia Atlanta 498715 61 Colorado Colorado Springs 457568 62 Connecticut Stamford 129775 63 South Dakota Rapid City 74388 64 Indiana Indianapolis 855164 65 North Dakota Fargo 124662 66 New Jersey Newark 281054 67 Rhode Island Warwick 81481 68 Nevada Las Vegas 641676 69 Wisconsin Milwaukee 592025 70 Indiana Fort Wayne 264488 71 South Dakota Aberdeen 27653 72 Mississippi Jackson 172638 73 Kansas Overland Park 190886 74 Vermont Rutland 15942 75 Oregon Portland 632309 76 Arkansas Little Rock 202591 77 Wyoming Laramie 32311 78 Minnesota Minneapolis 429606 79 Maryland Gaithersburg 67404 80 New Jersey Paterson 146199 81 Minnesota Rochester 223873 82 Utah West Valley City 136574 83 Alaska Anchorage 291538 84 Missouri Springfield 165794 85 Alabama Birmingham 200733 86 Illinois Chicago 2716000 87 Montana Billings 109577 88 Kentucky Lexington 323780 89 Vermont Burlington 42304 90 Pennsylvania Philadelphia 1567442 91 Tennessee Memphis 660388 92 Ohio Cincinnati 298165 93 Connecticut Bridgeport 144399 94 Iowa Cedar Rapids 132228 95 Indiana Evansville 119943 96 South Dakota Sioux Falls 186502 97 North Dakota Bismarck 74151 98 Michigan Detroit 672662 99 Pennsylvania Pittsburgh 305704 100 Delaware Newark 34544 101 Washington Spokane 230707 102 Alaska Fairbanks 31516 103 Montana Missoula 68220 104 Mississippi Gulfport 71375 105 Virginia Norfolk 244835 106 Pennsylvania Allentown 118577 107 Nebraska Lincoln 280849 108 New York Buffalo 256480 109 Alabama Montgomery 199518 110 Maryland Baltimore 622104 111 Wisconsin Green Bay 107395 112 Louisiana Baton Rouge 227715 113 Oklahoma Norman 124880 114 Michigan Warren 134056 115 Wyoming Cheyenne 64235 116 Kentucky Bowling Green 67226 117 Delaware Wilmington 70973 118 Virginia Virginia Beach 450189 119 Texas San Antonio 1532233 120 Florida Jacksonville 949611 121 Oklahoma Oklahoma City 649021 122 Washington Tacoma 213418 123 Nevada Henderson 310390 124 New York New York 8537673 125 Virginia Chesapeake 247036 126 Colorado Denver 716492 127 North Dakota Grand Forks 55231 128 Rhode Island Cranston 80566 129 Maryland Frederick 71726 130 Rhode Island Providence 179207 131 Missouri Kansas City 508090 132 Iowa Des Moines 214237 133 New Jersey Jersey City 280579 134 Wisconsin Madison 258054 135 New York Rochester 208046 136 Minnesota Saint Paul 308096 137 Arkansas Fayetteville 74880 138 Washington Seattle 787995 139 Hawaii Honolulu 337256 140 New Mexico Albuquerque 559277 141 Georgia Columbus 206922 142 Mississippi Southaven 55200 143 Louisiana Shreveport 194920 144 Illinois Naperville 147122 145 Tennessee Knoxville 190740 146 Kentucky Louisville 621349 147 Tennessee Nashville 634464 148 Nebraska Bellevue 272117 149 Connecticut New Haven 130322 150 Arizona Phoenix 1680992
BY STATE AND CITY row state city pop 1 Alabama Birmingham 200733 2 Alabama Mobile 195111 3 Alabama Montgomery 199518 4 Alaska Anchorage 291538 5 Alaska Fairbanks 31516 6 Alaska Juneau 31275 7 Arizona Mesa 508958 8 Arizona Phoenix 1680992 9 Arizona Tucson 548073 10 Arkansas Fayetteville 74880 ...
BY POP (NUMERIC DESC) AND CITY row state city pop 1 New York New York 8537673 2 California Los Angeles 3884307 3 Illinois Chicago 2716000 4 Texas Houston 2325502 5 Arizona Phoenix 1680992 6 Pennsylvania Philadelphia 1567442 7 Texas San Antonio 1532233 8 California San Diego 1423851 9 Texas Dallas 1335795 10 California San Jose 1021795 ...
BY POP (STRING) AND CITY row state city pop 1 Idaho Nampa 100200 2 New Mexico Rio Rancho 101008 3 California San Jose 1021795 4 Iowa Davenport 102320 5 Wisconsin Green Bay 107395 6 Montana Billings 109577 7 New Mexico Las Cruces 111385 8 New Hampshire Manchester 115644 9 Utah Provo 116288 10 Idaho Meridian 117322 ...
BY CITY AND STATE row state city pop 1 South Dakota Aberdeen 27653 2 New Mexico Albuquerque 559277 3 Pennsylvania Allentown 118577 4 Alaska Anchorage 291538 5 Georgia Atlanta 498715 6 Georgia Augusta 202679 7 Colorado Aurora 361710 8 Illinois Aurora 197757 9 Maryland Baltimore 622104 10 Maine Bangor 32178 ...
What's the performance of these sorts? I ran this example on some bigger tables, also with 2 keys and 1 data.
A you might have guessed, the customized Quicksort21 is much faster than the general one. Indication of timings in seconds.
Rows | Regina cust | Regina gen | ooRexx cust | ooRexx gen |
---|---|---|---|---|
1k | 0.01 | 0.02 | 0.01 | 0.03 |
10k | 0.11 | 0.28 | 0.18 | 0.70 |
100k | 1.5 | 3.8 | 2.3 | 11.7 |
1m | 18 | 120 | 30 | 120 |
Ring
aList= sort([:Eight = 8, :Two = 2, :Five = 5, :Nine = 9, :One = 1,
:Three = 3, :Six = 6, :Seven = 7, :Four = 4, :Ten = 10] , 2)
for item in aList
? item[1] + space(10-len(item[1])) + item[2]
next
- Output:
one 1 two 2 three 3 four 4 five 5 six 6 seven 7 eight 8 nine 9 ten 10
Ruby
Person = Struct.new(:name,:value) do
def to_s; "name:#{name}, value:#{value}" end
end
list = [Person.new("Joe",3),
Person.new("Bill",4),
Person.new("Alice",20),
Person.new("Harry",3)]
puts list.sort_by{|x|x.name}
puts
puts list.sort_by(&:value)
- Output:
name:Alice, value:20 name:Bill, value:4 name:Harry, value:3 name:Joe, value:3 name:Joe, value:3 name:Harry, value:3 name:Bill, value:4 name:Alice, value:20
Run BASIC
sqliteconnect #mem, ":memory:" ' create in memory db
mem$ = "CREATE TABLE people(num integer, name text,city text)"
#mem execute(mem$)
data "1","George","Redding","2","Fred","Oregon","3","Ben","Seneca","4","Steve","Fargo","5","Frank","Houston"
for i = 1 to 5 ' read data and place in memory DB
read num$ :read name$: read city$
#mem execute("INSERT INTO people VALUES(";num$;",'";name$;"','";city$;"')")
next i
#mem execute("SELECT * FROM people ORDER BY name") 'sort by name order
WHILE #mem hasanswer()
#row = #mem #nextrow()
num = #row num()
name$ = #row name$()
city$ = #row city$()
print num;" ";name$;" ";city$
WEND
3 Ben Seneca 5 Frank Houston 2 Fred Oregon 1 George Redding 4 Steve Fargo
Rust
use std::cmp::Ordering;
#[derive(Debug)]
struct Employee {
name: String,
category: String,
}
impl Employee {
fn new(name: &str, category: &str) -> Self {
Employee {
name: name.into(),
category: category.into(),
}
}
}
impl PartialEq for Employee {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
impl Eq for Employee {}
impl PartialOrd for Employee {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Employee {
fn cmp(&self, other: &Self) -> Ordering {
self.name.cmp(&other.name)
}
}
fn main() {
let mut employees = vec![
Employee::new("David", "Manager"),
Employee::new("Alice", "Sales"),
Employee::new("Joanna", "Director"),
Employee::new("Henry", "Admin"),
Employee::new("Tim", "Sales"),
Employee::new("Juan", "Admin"),
];
employees.sort();
for e in employees {
println!("{:<6} : {}", e.name, e.category);
}
}
- Output:
Alice : Sales David : Manager Henry : Admin Joanna : Director Juan : Admin Tim : Sales
Scala
case class Pair(name:String, value:Double)
val input = Array(Pair("Krypton", 83.798), Pair("Beryllium", 9.012182), Pair("Silicon", 28.0855))
input.sortBy(_.name) // Array(Pair(Beryllium,9.012182), Pair(Krypton,83.798), Pair(Silicon,28.0855))
// alternative versions:
input.sortBy(struct => (struct.name, struct.value)) // additional sort field (name first, then value)
input.sortWith((a,b) => a.name.compareTo(b.name) < 0) // arbitrary comparison function
Seed7
$ include "seed7_05.s7i";
const type: pair is new struct
var string: name is "";
var string: value is "";
end struct;
const func integer: compare (in pair: pair1, in pair: pair2) is
return compare(pair1.name, pair2.name);
const func string: str (in pair: aPair) is
return "(" <& aPair.name <& ", " <& aPair.value <& ")";
enable_output(pair);
const func pair: pair (in string: name, in string: value) is func
result
var pair: newPair is pair.value;
begin
newPair.name := name;
newPair.value := value;
end func;
var array pair: data is [] (
pair("Joe", "5531"),
pair("Adam", "2341"),
pair("Bernie", "122"),
pair("Walter", "1234"),
pair("David", "19"));
const proc: main is func
local
var pair: aPair is pair.value;
begin
data := sort(data);
for aPair range data do
writeln(aPair);
end for;
end func;
Output:
(Adam, 2341) (Bernie, 122) (David, 19) (Joe, 5531) (Walter, 1234)
Sidef
# Declare an array of pairs
var people = [['joe', 120], ['foo', 31], ['bar', 51]];
# Sort the array in-place by name
people.sort! {|a,b| a[0] <=> b[0] };
# Alternatively, we can use the `.sort_by{}` method
var sorted = people.sort_by { |item| item[0] };
# Display the sorted array
say people;
- Output:
[["bar", 51], ["foo", 31], ["joe", 120]]
Simula
BEGIN
CLASS COMPARABLE;;
COMPARABLE CLASS PAIR(N,V); TEXT N,V;;
CLASS COMPARATOR;
VIRTUAL:
PROCEDURE COMPARE IS
INTEGER PROCEDURE COMPARE(A, B); REF(COMPARABLE) A, B;;
BEGIN
END**OF**COMPARATOR;
COMPARATOR CLASS PAIRBYNAME;
BEGIN
INTEGER PROCEDURE COMPARE(A, B); REF(COMPARABLE) A, B;
BEGIN
COMPARE := IF A QUA PAIR.N < B QUA PAIR.N THEN -1 ELSE
IF A QUA PAIR.N > B QUA PAIR.N THEN +1 ELSE 0;
END;
END**OF**PAIRBYNAME;
PROCEDURE BUBBLESORT(A, C); NAME A; REF(COMPARABLE) ARRAY A; REF(COMPARATOR) C;
BEGIN
INTEGER LOW, HIGH, I;
BOOLEAN SWAPPED;
PROCEDURE SWAP(I, J); INTEGER I, J;
BEGIN
REF(COMPARABLE) TEMP;
TEMP :- A(I); A(I) :- A(J); A(J) :- TEMP;
END**OF**SWAP;
LOW := LOWERBOUND(A, 1);
HIGH := UPPERBOUND(A, 1);
SWAPPED := TRUE;
WHILE SWAPPED DO
BEGIN
SWAPPED := FALSE;
FOR I := LOW + 1 STEP 1 UNTIL HIGH DO
BEGIN
COMMENT IF THIS PAIR IS OUT OF ORDER ;
IF C.COMPARE(A(I - 1), A(I)) > 0 THEN
BEGIN
COMMENT SWAP THEM AND REMEMBER SOMETHING CHANGED ;
SWAP(I - 1, I);
SWAPPED := TRUE;
END;
END;
END;
END**OF**BUBBLESORT;
COMMENT ** MAIN PROGRAM **;
REF(PAIR) ARRAY A(1:5);
INTEGER I;
A(1) :- NEW PAIR( "JOE", "5531" );
A(2) :- NEW PAIR( "ADAM", "2341" );
A(3) :- NEW PAIR( "BERNIE", "122" );
A(4) :- NEW PAIR( "WALTER", "1234" );
A(5) :- NEW PAIR( "DAVID", "19" );
BUBBLESORT(A, NEW PAIRBYNAME);
FOR I:= 1 STEP 1 UNTIL 5 DO
BEGIN OUTTEXT(A(I).N); OUTCHAR(' '); OUTTEXT(A(I).V); OUTIMAGE; END;
OUTIMAGE;
END.
- Output:
ADAM 2341 BERNIE 122 DAVID 19 JOE 5531 WALTER 1234
SQL
We can treat the array of data structures as a table. An order by
clause in a query will sort the data.
-- setup
create table pairs (name varchar(16), value varchar(16));
insert into pairs values ('Fluffy', 'cat');
insert into pairs values ('Fido', 'dog');
insert into pairs values ('Francis', 'fish');
-- order them by name
select * from pairs order by name;
- Output:
NAME VALUE ---------------- ---------------- Fido dog Fluffy cat Francis fish
Swift
extension Sequence {
func sorted<Value>(
on: KeyPath<Element, Value>,
using: (Value, Value) -> Bool
) -> [Element] where Value: Comparable {
return withoutActuallyEscaping(using, do: {using -> [Element] in
return self.sorted(by: { using($0[keyPath: on], $1[keyPath: on]) })
})
}
}
struct Person {
var name: String
var role: String
}
let a = Person(name: "alice", role: "manager")
let b = Person(name: "bob", role: "worker")
let c = Person(name: "charlie", role: "driver")
print([c, b, a].sorted(on: \.name, using: <))
- Output:
[Runner.Person(name: "alice", role: "manager"), Runner.Person(name: "bob", role: "worker"), Runner.Person(name: "charlie", role: "driver")]
Tcl
Modeling the data structure being sorted as a list (a common Tcl practice):
set people {{joe 120} {foo 31} {bar 51}}
# sort by the first element of each pair
lsort -index 0 $people
UNIX Shell
With this language, everything is a string. My list of pairs is a string where a colon ":" separates "name:value", and a newline separates different pairs. Then I can use sort -t: -k1,1 to sort the pairs by name.
list="namez:order!
name space:in
name1:sort
name:Please"
newline="
"
dumplist() {
(
IFS=$newline
for pair in $list; do
(
IFS=:
set -- $pair
echo " $1 => $2"
)
done
)
}
echo "Original list:"
dumplist
list=`IFS=$newline; printf %s "$list" | sort -t: -k1,1`
echo "Sorted list:"
dumplist
Output:
Original list: namez => order! name space => in name1 => sort name => Please Sorted list: name => Please name space => in name1 => sort namez => order!
Ursala
The built in sort operator, -<, can be parameterized by an anonymous field specification and/or a relational predicate.
#import std
#cast %sWLW
examples =
(
-<&l <('z','a'),('x','c'),('y','b')>, # sorted by the left
-<&r <('z','a'),('x','c'),('y','b')>) # sorted by the right
output:
( <('x','c'),('y','b'),('z','a')>, <('z','a'),('y','b'),('x','c')>)
a more verbose example, showing a list of records of a user defined type sorted by a named field:
#import std
person :: name %s value %s
people =
<
person[name: 'Marilyn Monroe',value: 'priceless'],
person[name: 'Victor Hugo',value: 'millions'],
person[name: 'Johnny Carson',value: 'up there']>
#cast _person%L
example = (lleq+ ~name~~)-< people
output:
< person[name: 'Johnny Carson',value: 'up there'], person[name: 'Marilyn Monroe',value: 'priceless'], person[name: 'Victor Hugo',value: 'millions']>
Wren
import "./sort" for Cmp, Sort, Comparable
class Pair is Comparable {
construct new (name, value) {
_name = name
_value = value
}
name { _name }
value { _value }
compare(other) { Cmp.string.call(_name, other.name) }
toString { "{%(_name), %(_value)}" }
}
var pairs = [
Pair.new("grass", "green"),
Pair.new("snow", "white"),
Pair.new("sky", "blue"),
Pair.new("cherry", "red")
]
System.print("Before sorting:")
System.print(" " + pairs.join("\n "))
Sort.insertion(pairs)
System.print("\nAfter sorting:")
System.print(" " + pairs.join("\n "))
- Output:
Before sorting: {grass, green} {snow, white} {sky, blue} {cherry, red} After sorting: {cherry, red} {grass, green} {sky, blue} {snow, white}
XPL0
include c:\cxpl\stdlib;
char Dict(10,10);
int Entries;
proc BSort(A, N); \Bubble sort array A's key string into ascending order
char A; \address of array
int N; \number of items in array (size)
int B, I, J, T;
[B:= A; \B(I) accesses 32-bit pointers, not A(I) 8-bit bytes
for J:= N-1 downto 0 do
for I:= 0 to J-1 do
if StrCmp(A(I,1), A(I+1,1)) > 0 then
[T:= B(I); B(I):= B(I+1); B(I+1):= T]; \swap pointers
];
proc AddEntry(Letter, Greek); \Insert entry into associative array
char Letter, Greek;
[Dict(Entries,0):= Letter;
StrCopy(Greek, @Dict(Entries,1));
Entries:= Entries+1; \(limit checks ignored for simplicity)
];
int I;
[Entries:= 0;
AddEntry(^A, "alpha"); \add items in arbitrary order
AddEntry(^D, "delta");
AddEntry(^B, "beta");
AddEntry(^C, "gamma");
BSort(Dict, Entries); \sort entries by Greek name
for I:= 0 to Entries-1 do \show sorted entries
[ChOut(0, Dict(I,0)); ChOut(0, ^ ); Text(0, @Dict(I,1)); CrLf(0)];
]
- Output:
A alpha B beta D delta C gamma
zkl
The list of lists way is available or:
class P{var name,value;
fcn init(nm,val){name,value=vm.arglist}
fcn __opLT(p){name<p.name} // implementation of P1 < P2
}
// create list of pairs:
p:=List(P("sam","a"),P("fred","b"),P("chris","c"));
p.sort();
p.apply("name"); //-->L("chris","fred","sam")
- Programming Tasks
- Sorting Algorithms
- Sorting
- 11l
- AArch64 Assembly
- ACL2
- Action!
- Ada
- ALGOL 68
- AppleScript
- ARM Assembly
- Arturo
- ATS
- AutoHotkey
- AWK
- Babel
- BBC BASIC
- Bracmat
- C
- C sharp
- C++
- Clojure
- Common Lisp
- D
- Delphi
- E
- EchoLisp
- Elena
- Elixir
- Erlang
- Euphoria
- F Sharp
- Factor
- Fantom
- Fortran
- FreeBASIC
- Frink
- Fōrmulæ
- Go
- Groovy
- Haskell
- Icon
- Unicon
- J
- Java
- JavaScript
- Jq
- Julia
- Kotlin
- Lambdatalk
- Liberty BASIC
- Lua
- M2000 Interpreter
- Mathematica
- Wolfram Language
- MAXScript
- NetRexx
- Nim
- Objeck
- Objective-C
- OCaml
- Oforth
- Ol
- OoRexx
- Oz
- PARI/GP
- Pascal
- PascalABC.NET
- Perl
- Phix
- Phix/basics
- Phixmonti
- PicoLisp
- PowerShell
- PureBasic
- Python
- R
- Racket
- Raku
- REXX
- Ring
- Ruby
- Run BASIC
- Rust
- Scala
- Seed7
- Sidef
- Simula
- SQL
- Swift
- Tcl
- UNIX Shell
- Ursala
- Wren
- Wren-sort
- XPL0
- Zkl