Sort stability: Difference between revisions

From Rosetta Code
Content added Content deleted
m (added Category:Sorting)
(→‎{{header|REXX}}: replace the wrong program)
 
(18 intermediate revisions by 13 users not shown)
Line 29: Line 29:
(This [[wp:Stable_sort#Comparison_of_algorithms|Wikipedia table]] shows the stability of some common sort routines).
(This [[wp:Stable_sort#Comparison_of_algorithms|Wikipedia table]] shows the stability of some common sort routines).
<br><br>
<br><br>
=={{header|11l}}==
11l's in-built <code>sorted</code> function as well as the <code>sort</code> method of arrays are not guaranteed stable.

=={{header|AArch64 Assembly}}==
{{works with|as|Raspberry Pi 3B version Buster 64 bits}}
<syntaxhighlight lang="aarch64 assembly">
/* ARM assembly AARCH64 Raspberry PI 3B */
/* program stableSort641.s */
/* use merge sort and pointer table */
/* but use a extra table of pointer for the merge */
/*******************************************/
/* 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_country: //
.struct city_country + 8 // string pointer
city_end:
/*********************************/
/* Initialized data */
/*********************************/
.data
sMessResult: .asciz "Name : @ country : @ \n"
szMessSortName: .asciz "Sort table for name of city :\n"
szMessSortCountry: .asciz "Sort table for country : \n"
szCarriageReturn: .asciz "\n"

// cities name
szLondon: .asciz "London"
szNewyork: .asciz "New York"
szBirmin: .asciz "Birmingham"
szParis: .asciz "Paris"
// country name
szUK: .asciz "UK"
szUS: .asciz "US"
szFR: .asciz "FR"
.align 4
TableCities:
e1: .quad szLondon // address name string
.quad szUK // address country string
e2: .quad szParis
.quad szFR
e3: .quad szNewyork
.quad szUS
e4: .quad szBirmin
.quad szUK
e5: .quad szParis
.quad szUS
e6: .quad szBirmin
.quad szUS
/* pointers table */
ptrTableCities: .quad e1
.quad e2
.quad e3
.quad e4
.quad e5
.quad e6
.equ NBELEMENTS, (. - ptrTableCities) / 8
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
sZoneConv: .skip 24
ptrTableExtraSort: .skip 8 * NBELEMENTS
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: // entry of program
ldr x0,qAdrptrTableCities // address pointers table
bl displayTable

ldr x0,qAdrszMessSortName
bl affichageMess

ldr x0,qAdrptrTableCities // address pointers table
mov x1,0 // not use in routine
mov x2,NBELEMENTS - 1 // number of élements
mov x3,#city_name // sort by city name
mov x4,#'A' // alphanumeric
ldr x5,qAdrptrTableExtraSort
bl mergeSort
ldr x0,qAdrptrTableCities // address table
bl displayTable
ldr x0,qAdrszMessSortCountry
bl affichageMess

ldr x0,qAdrptrTableCities // address table
mov x1,0 // not use in routine
mov x2,NBELEMENTS - 1 // number of élements
mov x3,#city_country // sort by city country
mov x4,#'A' // alphanumeric
ldr x5,qAdrptrTableExtraSort
bl mergeSort
ldr x0,qAdrptrTableCities // 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
qAdrszMessSortName: .quad szMessSortName
qAdrptrTableExtraSort: .quad ptrTableExtraSort
qAdrszMessSortCountry: .quad szMessSortCountry
qAdrptrTableCities: .quad ptrTableCities
/******************************************************************/
/* merge sort */
/******************************************************************/
/* x0 contains the address of table */
/* x1 contains the index of first element */
/* x2 contains the number of element */
/* x3 contains the offset of area sort */
/* x4 contains the type of area sort N numeric A alpha */
/* x5 contains address extra area */
mergeSort:
stp x3,lr,[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
mov x6,x1 // save index first element
mov x7,x2 // save number of element
mov x11,x0 // save address table
cmp x2,x1 // end ?
ble 100f
add x9,x2,x1
lsr x9,x9,1 // number of element of each subset
mov x2,x9
bl mergeSort
mov x1,x9 // restaur number of element of each subset
add x1,x1,1
mov x2,x7 // restaur number of element
bl mergeSort // sort first subset
add x10,x9,1
1:
sub x1,x10,1
sub x8,x10,1
ldr x2,[x0,x1,lsl 3]
str x2,[x5,x8,lsl 3]
sub x10,x10,1
cmp x10,x6
bgt 1b
mov x10,x9
2:
add x1,x10,1
add x8,x7,x9
sub x8,x8,x10
ldr x2,[x0,x1,lsl 3]
str x2,[x5,x8,lsl 3]
add x10,x10,1
cmp x10,x7
blt 2b

mov x10,x6 //k
mov x1,x6 // i
mov x2,x7 // j
3:
mov x0,x5 // table address x1 = i x2 = j x3 = area sort offeset
bl comparArea
cmp x0,0
bgt 5f
blt 4f
// if equal and i < pivot
cmp x1,x9
ble 4f // inverse to stable
b 5f
4: // store element subset 1
mov x0,x5
ldr x6,[x5,x1, lsl 3]
str x6,[x11,x10, lsl 3]
add x1,x1,1
b 6f
5: // store element subset 2
mov x0,x5
ldr x6,[x5,x2, lsl 3]
str x6,[x11,x10, lsl 3]
sub x2,x2,1
6:
add x10,x10,1
cmp x10,x7
ble 3b
mov x0,x11

100:
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 x3,lr,[sp],16 // restaur 2 registers
ret // return to address lr x30
/******************************************************************/
/* comparison sort area */
/******************************************************************/
/* x0 contains the address of table */
/* x1 indice area sort 1 */
/* x2 indice area sort 2 */
/* x3 contains the offset of area sort */
/* x4 contains the type of area sort N numeric A alpha */
comparArea:
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
ldr x1,[x0,x1,lsl 3] // load pointer element 1
ldr x6,[x1,x3] // load area sort element 1
ldr x2,[x0,x2,lsl 3] // load pointer element 2
ldr x7,[x2,x3] // load area sort element 2
cmp x4,'A' // numeric or alpha ?
beq 1f
cmp x6,x7 // compare numeric value
blt 10f
bgt 11f
b 12f
1: // else compar alpha string
mov x8,#0
2:
ldrb w9,[x6,x8] // byte string 1
ldrb w5,[x7,x8] // byte string 2
cmp w9,w5
bgt 11f
blt 10f

cmp w9,#0 // end string 1
beq 12f // end comparaison
add x8,x8,#1 // else add 1 in counter
b 2b // and loop
10: // lower
mov x0,-1
b 100f
11: // highter
mov x0,1
b 100f
12: // equal
mov x0,0
100:
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

/******************************************************************/
/* 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
1: // loop display table
lsl x4,x3,#3 // offset element
ldr x6,[x2,x4] // load pointer
ldr x1,[x6,city_name]
ldr x0,qAdrsMessResult
bl strInsertAtCharInc // put name in message
ldr x1,[x6,city_country] // and put country in the message
bl strInsertAtCharInc // insert result at @ character
bl affichageMess // display message
add x3,x3,1
cmp x3,#NBELEMENTS
blt 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>
Name : London country : UK
Name : Paris country : FR
Name : New York country : US
Name : Birmingham country : UK
Name : Paris country : US
Name : Birmingham country : US

Sort table for name of city :
Name : Birmingham country : UK
Name : Birmingham country : US
Name : London country : UK
Name : New York country : US
Name : Paris country : FR
Name : Paris country : US

Sort table for country :
Name : Paris country : FR
Name : Birmingham country : UK
Name : London country : UK
Name : Birmingham country : US
Name : New York country : US
Name : Paris country : US
</pre>


=={{header|Ada}}==
=={{header|Ada}}==
Line 52: Line 376:
The task description doesn't specify what form the "table" takes, but here it's assumed to be a tab-delimited text.
The task description doesn't specify what form the "table" takes, but here it's assumed to be a tab-delimited text.


<lang applescript>set aTable to "UK London
<syntaxhighlight lang="applescript">set aTable to "UK London
US New York
US New York
US Birmingham
US Birmingham
Line 61: Line 385:
set stableSortedOnColumn1 to (do shell script ("sort -st'" & tab & "' -k1,1 <<<" & quoted form of aTable))
set stableSortedOnColumn1 to (do shell script ("sort -st'" & tab & "' -k1,1 <<<" & quoted form of aTable))
return "Stable sorted on column 2:" & (linefeed & stableSortedOnColumn2) & (linefeed & linefeed & ¬
return "Stable sorted on column 2:" & (linefeed & stableSortedOnColumn2) & (linefeed & linefeed & ¬
"Stable sorted on column 1:") & (linefeed & stableSortedOnColumn1)</lang>
"Stable sorted on column 1:") & (linefeed & stableSortedOnColumn1)</syntaxhighlight>


{{output}}
{{output}}
<lang applescript>"Stable sorted on column 2:
<syntaxhighlight lang="applescript">"Stable sorted on column 2:
US Birmingham
US Birmingham
UK Birmingham
UK Birmingham
Line 75: Line 399:
US New York
US New York
US Birmingham"
US Birmingham"
</syntaxhighlight>
</lang>

=={{header|Arturo}}==

<syntaxhighlight lang="arturo">records: @[
#[country: "UK", city: "London"]
#[country: "US", city: "New York"]
#[country: "US", city: "Birmingham"]
#[country: "UK", city: "Birmingham"]
]

print "Original order:"
loop records => print

print "\nSorted by country name:"
loop sort.by:'country records => print

print "\nSorted by city name:"
loop sort.by:'city records => print</syntaxhighlight>

{{out}}

<pre>Original order:
[country:UK city:London]
[country:US city:New York]
[country:US city:Birmingham]
[country:UK city:Birmingham]

Sorted by country name:
[country:UK city:London]
[country:UK city:Birmingham]
[country:US city:New York]
[country:US city:Birmingham]

Sorted by city name:
[country:US city:Birmingham]
[country:UK city:Birmingham]
[country:UK city:London]
[country:US city:New York]</pre>


=={{header|AutoHotkey}}==
=={{header|AutoHotkey}}==
Autohotkey has got a build-in sorting method for tables, which is stable.
Autohotkey has got a build-in sorting method for tables, which is stable.
<lang AutoHotkey>Table =
<syntaxhighlight lang="autohotkey">Table =
(
(
UK, London
UK, London
Line 118: Line 480:
ButtonSortCities:
ButtonSortCities:
LV_ModifyCol(3, "Sort")
LV_ModifyCol(3, "Sort")
Return</lang>
Return</syntaxhighlight>


=={{header|AWK}}==
=={{header|AWK}}==
<syntaxhighlight lang="awk">
<lang AWK>
# syntax: GAWK -f SORT_STABILITY.AWK [-v width=x] -v field=x SORT_STABILITY.TXT
# syntax: GAWK -f SORT_STABILITY.AWK [-v width=x] -v field=x SORT_STABILITY.TXT
#
#
Line 149: Line 511:
exit(0)
exit(0)
}
}
</syntaxhighlight>
</lang>
<p>input:</p>
<p>input:</p>
<pre>
<pre>
Line 226: Line 588:
These functions use merge sort algorithm.
These functions use merge sort algorithm.
The sorting algorithm will be stable as long as the given function returns true for values considered equal:
The sorting algorithm will be stable as long as the given function returns true for values considered equal:
<lang elixir>cities = [ {"UK", "London"},
<syntaxhighlight lang="elixir">cities = [ {"UK", "London"},
{"US", "New York"},
{"US", "New York"},
{"US", "Birmingham"},
{"US", "Birmingham"},
Line 234: Line 596:
IO.inspect Enum.sort(cities, fn a,b -> elem(a,0) >= elem(b,0) end)
IO.inspect Enum.sort(cities, fn a,b -> elem(a,0) >= elem(b,0) end)
IO.inspect Enum.sort_by(cities, fn {country, _city} -> country end)
IO.inspect Enum.sort_by(cities, fn {country, _city} -> country end)
IO.inspect Enum.sort_by(cities, fn {_country, city} -> city end)</lang>
IO.inspect Enum.sort_by(cities, fn {_country, city} -> city end)</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 244: Line 606:


'''Note:''' If the function does not return true, the sorting is not stable and the order of equal terms may be shuffled:
'''Note:''' If the function does not return true, the sorting is not stable and the order of equal terms may be shuffled:
<lang elixir>IO.inspect Enum.sort(cities, fn a,b -> elem(a,0) > elem(b,0) end)</lang>
<syntaxhighlight lang="elixir">IO.inspect Enum.sort(cities, fn a,b -> elem(a,0) > elem(b,0) end)</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 261: Line 623:


=={{header|Fortran}}==
=={{header|Fortran}}==
The language does not offer an in-built sort facility. Numerous libraries exist, which may or may not have documentation on their sort routine's stability.

=={{header|FreeBASIC}}==
The language does not offer an in-built sort facility. Numerous libraries exist, which may or may not have documentation on their sort routine's stability.
The language does not offer an in-built sort facility. Numerous libraries exist, which may or may not have documentation on their sort routine's stability.


=={{header|GAP}}==
=={{header|GAP}}==
<lang gap># According to section 21.18 of the reference manual, Sort is not stable (it's a Shell sort).
<syntaxhighlight lang="gap"># According to section 21.18 of the reference manual, Sort is not stable (it's a Shell sort).
# However, SortingPerm is stable. We will see it on an example, showing indexes of elements after the sort.
# However, SortingPerm is stable. We will see it on an example, showing indexes of elements after the sort.


Line 280: Line 645:
PrintArray(TransposedMat(List([1 .. n], i -> [a[i], b[i]])));
PrintArray(TransposedMat(List([1 .. n], i -> [a[i], b[i]])));
# [ [ 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B' ],
# [ [ 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B' ],
# [ 1, 2, 4, 8, 11, 13, 14, 16, 19, 3, 5, 6, 7, 9, 10, 12, 15, 17, 18, 20 ] ]</lang>
# [ 1, 2, 4, 8, 11, 13, 14, 16, 19, 3, 5, 6, 7, 9, 10, 12, 15, 17, 18, 20 ] ]</syntaxhighlight>


=={{header|Go}}==
=={{header|Go}}==
Line 291: Line 656:
{{trans|Java}}
{{trans|Java}}
{{works with|Groovy|1.8.1}}
{{works with|Groovy|1.8.1}}
<lang groovy>def cityList = ['UK London', 'US New York', 'US Birmingham', 'UK Birmingham',].asImmutable()
<syntaxhighlight lang="groovy">def cityList = ['UK London', 'US New York', 'US Birmingham', 'UK Birmingham',].asImmutable()
[
[
'Sort by city': { city -> city[4..-1] },
'Sort by city': { city -> city[4..-1] },
Line 300: Line 665:
println "\nAfter ${label}"
println "\nAfter ${label}"
cityList.sort(false, orderBy).each{ println it }
cityList.sort(false, orderBy).each{ println it }
}</lang>
}</syntaxhighlight>


Output:
Output:
Line 345: Line 710:


The following sample demonstrates Java's sort stability:
The following sample demonstrates Java's sort stability:
<lang Java>import java.util.Arrays;
<syntaxhighlight lang="java">import java.util.Arrays;
import java.util.Comparator;
import java.util.Comparator;


Line 391: Line 756:
System.out.println();
System.out.println();
}
}
}</lang>
}</syntaxhighlight>
;Output
;Output
<pre>
<pre>
Line 424: Line 789:
At the time of writing this is already implemented in in Node.js and in the JS interpreters of all major browsers, including Microsoft Edge, but not according to the Mozilla implementations table, the older Internet Explorer. In earlier interpreters, sort stability depends on particular implementations.
At the time of writing this is already implemented in in Node.js and in the JS interpreters of all major browsers, including Microsoft Edge, but not according to the Mozilla implementations table, the older Internet Explorer. In earlier interpreters, sort stability depends on particular implementations.


<lang javascript>ary = [["UK", "London"], ["US", "New York"], ["US", "Birmingham"], ["UK", "Birmingham"]]
<syntaxhighlight lang="javascript">ary = [["UK", "London"], ["US", "New York"], ["US", "Birmingham"], ["UK", "Birmingham"]]
print(ary);
print(ary);


Line 430: Line 795:
print(ary);
print(ary);


/* a stable sort will output ["US", "Birmingham"] before ["UK", "Birmingham"] */</lang>
/* a stable sort will output ["US", "Birmingham"] before ["UK", "Birmingham"] */</syntaxhighlight>


Stable implementations:
Stable implementations:
Line 450: Line 815:
As of January 18, 2016 (Commit SHA 7835a72), the builtin sorting filters (notably sort/0 and sort_by/1) are stable; prior to that, stability was platform-dependent. This means that stability is NOT guaranteed in jq 1.5 or earlier. In the following, a version of jq with sorting stability has been used.
As of January 18, 2016 (Commit SHA 7835a72), the builtin sorting filters (notably sort/0 and sort_by/1) are stable; prior to that, stability was platform-dependent. This means that stability is NOT guaranteed in jq 1.5 or earlier. In the following, a version of jq with sorting stability has been used.


<lang jq>[["UK", "London"],
<syntaxhighlight lang="jq">[["UK", "London"],
["US", "New York"],
["US", "New York"],
["US", "Birmingham"],
["US", "Birmingham"],
["UK", "Birmingham"]]
["UK", "Birmingham"]]
| sort_by(.[1])</lang>
| sort_by(.[1])</syntaxhighlight>


Invocation:
Invocation:
Line 476: Line 841:
=={{header|Kotlin}}==
=={{header|Kotlin}}==
The collections in Kotlin's standard library are thin wrappers around the corresponding JDK collections and, since the latter's sort methods are stable, so too are Kotlin's standard sort functions.
The collections in Kotlin's standard library are thin wrappers around the corresponding JDK collections and, since the latter's sort methods are stable, so too are Kotlin's standard sort functions.
<lang scala>// version 1.1.51
<syntaxhighlight lang="scala">// version 1.1.51


fun main(args: Array<String>) {
fun main(args: Array<String>) {
Line 485: Line 850:
// sort by city
// sort by city
println("By city : ${cities.sortedBy { it.drop(3) } }")
println("By city : ${cities.sortedBy { it.drop(3) } }")
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}
Line 497: Line 862:
Arrays can be sorted in two “built in" ways in Lasso:
Arrays can be sorted in two “built in" ways in Lasso:


<lang Lasso>//Single param array:
<syntaxhighlight lang="lasso">//Single param array:
array->sort
array->sort


Line 504: Line 869:


//The array can also be ordered by multiple values:
//The array can also be ordered by multiple values:
with i in array order by #i->second, #i->first do => { … } </lang>
with i in array order by #i->second, #i->first do => { … } </syntaxhighlight>


Sorting of arrays by either method uses “Qucksort” and is therefore unstable. A simulation of increasing sort stability would be introduced with additional params such as the example of ordering by the second then the first pair values in the example above - but would not be guaranteed stable.
Sorting of arrays by either method uses “Qucksort” and is therefore unstable. A simulation of increasing sort stability would be introduced with additional params such as the example of ordering by the second then the first pair values in the example above - but would not be guaranteed stable.
Line 511: Line 876:


Sort by second value only:
Sort by second value only:
<lang Lasso>local(a = array('UK'='London','US'='New York','US'='Birmingham','UK'='Birmingham'))
<syntaxhighlight lang="lasso">local(a = array('UK'='London','US'='New York','US'='Birmingham','UK'='Birmingham'))
with i in #a order by #i->second do => {^ #i->first+' - '+#i->second+'\r' ^}</lang>
with i in #a order by #i->second do => {^ #i->first+' - '+#i->second+'\r' ^}</syntaxhighlight>
{{out}}
{{out}}
<pre>US - Birmingham
<pre>US - Birmingham
Line 520: Line 885:


Sort by second then by first:
Sort by second then by first:
<lang Lasso>local(a = array('UK'='London','US'='New York','US'='Birmingham','UK'='Birmingham'))
<syntaxhighlight lang="lasso">local(a = array('UK'='London','US'='New York','US'='Birmingham','UK'='Birmingham'))
with i in #a order by #i->second, #i->first do => {^ #i->first+' - '+#i->second+'\r' ^}</lang>
with i in #a order by #i->second, #i->first do => {^ #i->first+' - '+#i->second+'\r' ^}</syntaxhighlight>
{{out}}
{{out}}
<pre>UK - Birmingham
<pre>UK - Birmingham
Line 534: Line 899:


Here's an example showing that SORT indeed unstable.
Here's an example showing that SORT indeed unstable.
<syntaxhighlight lang="lb">
<lang lb>
randomize 0.5
randomize 0.5
N=15
N=15
Line 563: Line 928:
end if
end if
next
next
</syntaxhighlight>
</lang>
{{Out}}
{{Out}}
<pre>
<pre>
Line 610: Line 975:


Here is the stable sort
Here is the stable sort
<syntaxhighlight lang="m2000 interpreter">
<lang M2000 Interpreter>
Module Stable {
Module Stable {
Inventory queue alfa
Inventory queue alfa
Line 638: Line 1,003:
US Birmingham
US Birmingham


</syntaxhighlight>
</lang>




Line 644: Line 1,009:
We can sort in on key only. Lets make keys with two fields (based on fields lengths, except for last one)
We can sort in on key only. Lets make keys with two fields (based on fields lengths, except for last one)


<syntaxhighlight lang="m2000 interpreter">
<lang M2000 Interpreter>
Module Stable1 {
Module Stable1 {
Inventory queue alfa
Inventory queue alfa
Line 672: Line 1,037:
US New York
US New York


</syntaxhighlight>
</lang>


Now second column is sorting (but it is one column all, no two columns). So lets see the unstable sort. Because all keys now are unique we just remove queue from Inventory definition.
Now second column is sorting (but it is one column all, no two columns). So lets see the unstable sort. Because all keys now are unique we just remove queue from Inventory definition.
<syntaxhighlight lang="m2000 interpreter">
<lang M2000 Interpreter>
Module Stable2 {
Module Stable2 {
Inventory alfa
Inventory alfa
Line 703: Line 1,068:
US New York
US New York


</syntaxhighlight>
</lang>


So now we see that using unique keys in either type of inventories we get same output.
So now we see that using unique keys in either type of inventories we get same output.
Line 713: Line 1,078:
If we delete a key in normal inventory we miss the sort order. We can't delete keys in queue inventories, but we can drop from the last append a number of keys. Also Exist() function in queue inventories always find the last entry (for same keys), until that dropped, so with next use of Exist(pointer_to_inventory, key_case_sensitive$) we find the previous one. We can use keys as numbers, but they stored as strings.
If we delete a key in normal inventory we miss the sort order. We can't delete keys in queue inventories, but we can drop from the last append a number of keys. Also Exist() function in queue inventories always find the last entry (for same keys), until that dropped, so with next use of Exist(pointer_to_inventory, key_case_sensitive$) we find the previous one. We can use keys as numbers, but they stored as strings.


=={{header|Mathematica}}==
=={{header|Mathematica}}/{{header|Wolfram Language}}==
Sort is not always stable. Ordering, which gives a list of indices such as to put the elements of the list in order, is stable. An example would be to sort the list (of lists) {{1, 2, 3}, {4, 5, 6}, {5, 4, 3}, {9, 5, 1}}, and doing so by looking at the 2nd value of each list:
Sort is not always stable. Ordering, which gives a list of indices such as to put the elements of the list in order, is stable. An example would be to sort the list (of lists) {{1, 2, 3}, {4, 5, 6}, {5, 4, 3}, {9, 5, 1}}, and doing so by looking at the 2nd value of each list:
<lang Mathematica>mylist = {{1, 2, 3}, {4, 5, 6}, {5, 4, 3}, {9, 5, 1}};
<syntaxhighlight lang="mathematica">mylist = {{1, 2, 3}, {4, 5, 6}, {5, 4, 3}, {9, 5, 1}};
Sort[mylist, (#1[[2]] < #2[[2]]) &]
Sort[mylist, (#1[[2]] < #2[[2]]) &]
#[[Ordering[#[[All, 2]]]]] &[mylist]</lang>
#[[Ordering[#[[All, 2]]]]] &[mylist]</syntaxhighlight>
gives:
gives:
<lang Mathematica>{{1, 2, 3}, {5, 4, 3}, {9, 5, 1}, {4, 5, 6}}
<syntaxhighlight lang="mathematica">{{1, 2, 3}, {5, 4, 3}, {9, 5, 1}, {4, 5, 6}}
{{1, 2, 3}, {5, 4, 3}, {4, 5, 6}, {9, 5, 1}}</lang>
{{1, 2, 3}, {5, 4, 3}, {4, 5, 6}, {9, 5, 1}}</syntaxhighlight>
Showing that Sort is unstable, and that by using input[[Ordering[input]]] Ordering provides a way to make a stable sort.
Showing that Sort is unstable, and that by using input[[Ordering[input]]] Ordering provides a way to make a stable sort.


Line 729: Line 1,094:
Java's [http://java.sun.com/javase/6/docs/api/java/util/Collections.html#sort(java.util.List) Collections.sort()] and [http://java.sun.com/javase/6/docs/api/java/util/Arrays.html#sort(java.lang.Object%5B%5D) Arrays.sort()] methods are guaranteed stable. The following sample takes advantage of this to demonstrate sort stability.
Java's [http://java.sun.com/javase/6/docs/api/java/util/Collections.html#sort(java.util.List) Collections.sort()] and [http://java.sun.com/javase/6/docs/api/java/util/Arrays.html#sort(java.lang.Object%5B%5D) Arrays.sort()] methods are guaranteed stable. The following sample takes advantage of this to demonstrate sort stability.


<lang NetRexx>/* NetRexx */
<syntaxhighlight lang="netrexx">/* NetRexx */
options replace format comments java crossref savelog symbols nobinary
options replace format comments java crossref savelog symbols nobinary


Line 784: Line 1,149:
method compare(lft = Object, rgt = Object) public binary returns int
method compare(lft = Object, rgt = Object) public binary returns int
return (String lft).substring(0, 2).compareTo((String rgt).substring(0, 2))
return (String lft).substring(0, 2).compareTo((String rgt).substring(0, 2))
</syntaxhighlight>
</lang>
;Output
;Output
<pre>
<pre>
Line 814: Line 1,179:
=={{header|Nim}}==
=={{header|Nim}}==
Default Nim sort in the algorithm module is stable.
Default Nim sort in the algorithm module is stable.
<syntaxhighlight lang="nim">import algorithm

const Records = [(country: "UK", city: "London"),
(country: "US", city: "New York"),
(country: "US", city: "Birmingham"),
(country: "UK", city: "Birmingham")]

echo "Original order:"
for record in Records:
echo record.country, " ", record.city
echo()

echo "Sorted by city name:"
for record in Records.sortedByIt(it.city):
echo record.country, " ", record.city
echo()

echo "Sorted by country name:"
for record in Records.sortedByIt(it.country):
echo record.country, " ", record.city</syntaxhighlight>

{{out}}
<pre>Original order:
UK London
US New York
US Birmingham
UK Birmingham

Sorted by city name:
US Birmingham
UK Birmingham
UK London
US New York

Sorted by country name:
UK London
UK Birmingham
US New York
US Birmingham</pre>


=={{header|OCaml}}==
=={{header|OCaml}}==
Line 820: Line 1,224:
=={{header|ooRexx}}==
=={{header|ooRexx}}==
Open Object Rexx provides sort methods (<code>sort</code> and <code>sortWith(comparator)</code>) for its collection classes. By default these sort methods are implemented via an unstable <em>Quicksort</em> algorithm but the language does provide stable sorting methods (<code>stableSort</code> and <code>stableSortWith(comparator)</code>) implemented via a stable <em>Mergesort</em> algorithm.
Open Object Rexx provides sort methods (<code>sort</code> and <code>sortWith(comparator)</code>) for its collection classes. By default these sort methods are implemented via an unstable <em>Quicksort</em> algorithm but the language does provide stable sorting methods (<code>stableSort</code> and <code>stableSortWith(comparator)</code>) implemented via a stable <em>Mergesort</em> algorithm.
<lang ooRexx>/* Rexx */
<syntaxhighlight lang="oorexx">/* Rexx */
Do
Do
cities = .array~of('UK London', 'US New York', 'US Birmingham', 'UK Birmingham',)
cities = .array~of('UK London', 'US New York', 'US Birmingham', 'UK Birmingham',)
Line 863: Line 1,267:
End
End
Exit
Exit
</syntaxhighlight>
</lang>
;Output
;Output
<pre>
<pre>
Line 904: Line 1,308:
=={{header|OpenEdge/Progress}}==
=={{header|OpenEdge/Progress}}==
The results can be forced to stable by ''additionally'' sorting on the ROWID of the record. If you leave the additional sort out, the indexes on the temp-table can influence the result.
The results can be forced to stable by ''additionally'' sorting on the ROWID of the record. If you leave the additional sort out, the indexes on the temp-table can influence the result.
<lang progress>DEFINE TEMP-TABLE tt
<syntaxhighlight lang="progress">DEFINE TEMP-TABLE tt
FIELD country AS CHAR FORMAT 'x(2)'
FIELD country AS CHAR FORMAT 'x(2)'
FIELD city AS CHAR FORMAT 'x(16)'
FIELD city AS CHAR FORMAT 'x(16)'
Line 928: Line 1,332:
MESSAGE
MESSAGE
cc[1] SKIP(1) cc[2]
cc[1] SKIP(1) cc[2]
VIEW-AS ALERT-BOX.</lang>
VIEW-AS ALERT-BOX.</syntaxhighlight>


'''Output:'''
'''Output:'''
Line 958: Line 1,362:


Example:
Example:
<lang oz>declare
<syntaxhighlight lang="oz">declare
Cities = ['UK'#'London'
Cities = ['UK'#'London'
'US'#'New York'
'US'#'New York'
Line 968: Line 1,372:


%% sort by country; NOT stable because '<' is not reflexiv
%% sort by country; NOT stable because '<' is not reflexiv
{Show {Sort Cities fun {$ A B} A.1 < B.1 end}}</lang>
{Show {Sort Cities fun {$ A B} A.1 < B.1 end}}</syntaxhighlight>


=={{header|PARI/GP}}==
=={{header|PARI/GP}}==
Line 978: Line 1,382:
=={{header|Perl}}==
=={{header|Perl}}==
The stability of Perl's in-built [http://perldoc.perl.org/functions/sort.html sort] function is version-dependent. If you want to guarantee a stable sort from it, you should use the following [http://perldoc.perl.org/sort.html sort pragma]:
The stability of Perl's in-built [http://perldoc.perl.org/functions/sort.html sort] function is version-dependent. If you want to guarantee a stable sort from it, you should use the following [http://perldoc.perl.org/sort.html sort pragma]:
<lang perl>use sort 'stable';</lang>
<syntaxhighlight lang="perl">use sort 'stable';</syntaxhighlight>


=={{header|Phix}}==
=={{header|Phix}}==
The standard sort method is merge sort, which is apparently stable, though I would be reluctant to guarantee that, or rely on it, especially given
The standard sort method is merge sort, which is apparently stable, though I would be reluctant to guarantee that, or rely on it, especially given that a simple tag sort is irrefutably stable since it explicitly orders by tag (aka original position) within any equal keys.
<!--<syntaxhighlight lang="phix">(phixonline)-->
that a simple tag sort is guaranteed stable by dint of ordering by tag should the keys be equal.
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<lang Phix>sequence test = {{"UK","London"},
<span style="color: #004080;">sequence</span> <span style="color: #000000;">test</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #008000;">"UK"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"London"</span><span style="color: #0000FF;">},</span>
{"US","New York"},
<span style="color: #0000FF;">{</span><span style="color: #008000;">"US"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"New York"</span><span style="color: #0000FF;">},</span>
{"US","Birmingham"},
<span style="color: #0000FF;">{</span><span style="color: #008000;">"US"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Birmingham"</span><span style="color: #0000FF;">},</span>
{"UK","Birmingham"}}
<span style="color: #0000FF;">{</span><span style="color: #008000;">"UK"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Birmingham"</span><span style="color: #0000FF;">}}</span>

---------------------
<span style="color: #000080;font-style:italic;">---------------------
-- probably stable --
-- probably stable --
---------------------
---------------------</span>
function cmp(object a, object b)
<span style="color: #008080;">function</span> <span style="color: #000000;">cmp</span><span style="color: #0000FF;">(</span><span style="color: #004080;">object</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">object</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">)</span>
return compare(a[1],b[1])
<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>
end function
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
test = custom_sort(routine_id("cmp"),test)
<span style="color: #7060A8;">pp</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">custom_sort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cmp</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">test</span><span style="color: #0000FF;">)),{</span><span style="color: #004600;">pp_Nest</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">})</span>
pp(test,{pp_Nest,1})

-----------------------
<span style="color: #000080;font-style:italic;">-----------------------
-- guaranteed stable --
-- guaranteed stable --
-----------------------
-----------------------</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">tag_cmp</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">)</span>
function tag_cmp(integer i, integer j)
<span style="color: #004080;">integer</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">compare</span><span style="color: #0000FF;">(</span><span style="color: #000000;">test</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">2</span><span style="color: #0000FF;">],</span><span style="color: #000000;">test</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">][</span><span style="color: #000000;">2</span><span style="color: #0000FF;">])</span>
return compare({test[i][1],i},{test[j][1],j})
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">compare</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">j</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- (see note)</span>
-- return compare(test[i][1],test[j][1])
<span style="color: #008080;">return</span> <span style="color: #000000;">c</span>
end function
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
sequence tags = custom_sort(routine_id("tag_cmp"),shuffle(tagset(4)))
<span style="color: #004080;">sequence</span> <span style="color: #000000;">tags</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">custom_sort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tag_cmp</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">shuffle</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #000000;">4</span><span style="color: #0000FF;">)))</span>
for i=1 to length(tags) do
<span style="color: #7060A8;">pp</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">extract</span><span style="color: #0000FF;">(</span><span style="color: #000000;">test</span><span style="color: #0000FF;">,</span><span style="color: #000000;">tags</span><span style="color: #0000FF;">),{</span><span style="color: #004600;">pp_Nest</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">})</span>
?test[tags[i]]
<!--</syntaxhighlight>-->
end for</lang>
{{Out}}
{{Out}}
<pre>
<pre>
{{"UK", "London"},
{{`US`, `Birmingham`},
{"UK", "Birmingham"},
{`UK`, `Birmingham`},
{"US", "New York"},
{`UK`, `London`},
{"US", "Birmingham"}}
{`US`, `New York`}}
{{`US`, `Birmingham`},
{"UK","London"}
{"UK","Birmingham"}
{`UK`, `Birmingham`},
{`UK`, `London`},
{"US","New York"}
{"US","Birmingham"}
{`US`, `New York`}}
</pre>
</pre>
The commented-out line in tag_cmp is unstable, or rather probably stable wrt the shuffle, whereas the active line guarantees
Commenting out the c=0 fixup in tag_cmp makes it unstable, or rather probably stable wrt the shuffle, and sometimes shows the first two lines flipped, whereas the active line guarantees original (pre-shuffle) ordering, even if an unstable underlying sort method were used.
Of course test=sort(test) guarantees alphabetical on second column within matching first column. Lastly, preserving a primary tag sort ordering within a secondary tag sort is a bit more mind-bending, but even that is not particularly difficult.
original (pre-shuffle) ordering, even if an unstable underlying sort method were used.
Obviously, written the way it is above, the guaranteed part only guarantees not to upset what the probably part left behind, and of course test=sort(test) guarantees alphabetical on second column within matching first column. Lastly, preserving a primary tag sort ordering within a secondary tag sort is a bit more mind-bending, but even that is not particularly difficult.


=={{header|PHP}}==
=={{header|PHP}}==
Line 1,034: Line 1,437:
=={{header|Python}}==
=={{header|Python}}==
Python's in-built [http://docs.python.org/library/functions.html#sorted sorted] function as well as the [http://docs.python.org/library/stdtypes.html#mutable-sequence-types sort method of lists] are guaranteed stable (since version 2.3). (For even more information on the underlying routine, [[wp:timsort]], see [http://svn.python.org/projects/python/trunk/Objects/listsort.txt this]).
Python's in-built [http://docs.python.org/library/functions.html#sorted sorted] function as well as the [http://docs.python.org/library/stdtypes.html#mutable-sequence-types sort method of lists] are guaranteed stable (since version 2.3). (For even more information on the underlying routine, [[wp:timsort]], see [http://svn.python.org/projects/python/trunk/Objects/listsort.txt this]).


=={{header|Quackery}}==

The inbuilt sort is stable.


=={{header|R}}==
=={{header|R}}==
R uses shell sort (stable) or quick sort (unstable). An easy way to show the difference is names to vector entries, then check if names are still ordered after sorting.
R uses shell sort (stable) or quick sort (unstable). An easy way to show the difference is names to vector entries, then check if names are still ordered after sorting.


<syntaxhighlight lang="r">
<lang R>
# First, define a bernoulli sample, of length 26.
# First, define a bernoulli sample, of length 26.
x <- sample(c(0, 1), 26, replace=T)
x <- sample(c(0, 1), 26, replace=T)
Line 1,061: Line 1,469:
# e h j n q s u x z a b c d f g i k l m o p r t v w y
# e h j n q s u x z a b c d f g i k l m o p r t v w y
# 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
# 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
</syntaxhighlight>
</lang>


=={{header|Racket}}==
=={{header|Racket}}==
Line 1,067: Line 1,475:
Racket comes with a standard <tt>sort</tt> function, which is documented [[http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28lib._racket%2Fprivate%2Flist..rkt%29._sort%29%29 here]]. It is documented as stable.
Racket comes with a standard <tt>sort</tt> function, which is documented [[http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28lib._racket%2Fprivate%2Flist..rkt%29._sort%29%29 here]]. It is documented as stable.


<syntaxhighlight lang="racket">
<lang Racket>
#lang racket
#lang racket


Line 1,085: Line 1,493:
;; -> '(("US" "Birmingham") ("UK" "Birmingham")
;; -> '(("US" "Birmingham") ("UK" "Birmingham")
;; ("UK" "London") ("US" "New York"))
;; ("UK" "London") ("US" "New York"))
</syntaxhighlight>
</lang>


=={{header|Raku}}==
=={{header|Raku}}==
Line 1,093: Line 1,501:


Short demonstration for sorting only on the second item of each array:
Short demonstration for sorting only on the second item of each array:
<lang perl6>use v6;
<syntaxhighlight lang="raku" line>use v6;
my @cities =
my @cities =
['UK', 'London'],
['UK', 'London'],
Line 1,101: Line 1,509:
;
;


.say for @cities.sort: { .[1] };</lang>
.say for @cities.sort: { .[1] };</syntaxhighlight>


=={{header|REBOL}}==
=={{header|REBOL}}==
<lang rebol>; REBOL's sort function is not stable by default. You need to use a custom comparator to make it so.
<syntaxhighlight lang="rebol">; REBOL's sort function is not stable by default. You need to use a custom comparator to make it so.


blk: [
blk: [
Line 1,121: Line 1,529:
UK Birmingham
UK Birmingham
]
]
sort/skip/compare blk 2 func [a b] [either a < b [-1] [either a > b [1] [0]]]</lang>
sort/skip/compare blk 2 func [a b] [either a < b [-1] [either a > b [1] [0]]]</syntaxhighlight>


=={{header|REXX}}==
=={{header|REXX}}==
<syntaxhighlight lang="rexx"></syntaxhighlight>
Classic REXX has no built-in routines for sorting, so this programming example uses a classic ''bubble sort'' &nbsp; (which is stable).
<lang rexx>/*REXX program sorts a (stemmed) array using a (stable) bubble─sort algorithm. */
/*REXX program sorts a (stemmed) array */
call gen@ /*generate the array elements (strings)*/
/* replacing the wrong program published here earlier */
call show 'before sort' /*show the before array elements. */
call gena /*generate the array elements (strings)*/
say copies('▒', 50) /*show a separator line between shows. */
call show 'before sort' /*show the before array elements. */
call stableSort
call bubbleSort # /*invoke the bubble sort. */
exit
call show ' after sort' /*show the after array elements. */
/*----------------------------------------------------------------------------*/
exit /*stick a fork in it, we're all done. */
stableSort: procedure expose a.
/*──────────────────────────────────────────────────────────────────────────────────────*/
parse Value '' With l1 l2
bubbleSort: procedure expose @.; parse arg n; m=n-1 /*N: number of array elements. */
Do i=1 To a.0
do m=m for m by -1 until ok; ok=1 /*keep sorting array until done.*/
parse Var a.i f1 f2
do j=1 for m; k=j+1; if @.j<=@.k then iterate /*Not out─of─order?*/
f2=translate(f2,'_',' ')
_=@.j; @.j=@.k; @.k=_; ok=0 /*swap 2 elements; flag as ¬done*/
If pos(f1,l1)=0 Then l1=l1 f1
end /*j*/
If pos(f2,l2)=0 Then l2=l2 f2
end /*m*/
return
End
l1=wordsort(l1)
/*──────────────────────────────────────────────────────────────────────────────────────*/
l2=wordsort(l2)
gen@: @.=; @.1 = 'UK London'
Say ''
@.2 = 'US New York'
Say 'sorted by country'
@.3 = 'US Birmingham'
Do While l1<>''
@.4 = 'UK Birmingham'
Parse Var l1 f1s l1
do #=1 while @.#\==''; end; #=#-1 /*determine how many entries in list. */
return
Do i=1 To a.0
parse Var a.i f1 f2
/*──────────────────────────────────────────────────────────────────────────────────────*/
If f1=f1s Then
show: do j=1 for #; say ' element' right(j,length(#)) arg(1)":" @.j; end; return</lang>
Say a.i
'''output''' &nbsp; using the default list:
End
End
Say ''
Say 'sorted by city'
Do While l2<>''
Parse Var l2 f2s l2
Do i=1 To a.0
parse Var a.i f1 f2
If translate(f2,'_',' ')=f2s Then
Say a.i
End
End
/*---------------------------------------------------------------------------------*/
gena: a.0=0
Call store 'UK London'
Call store 'US New York'
Call store 'US Birmingham'
Call store 'UK Birmingham'
Return
store:
z=a.0+1
a.z=arg(1)
a.0=z
Return
show:
Say arg(1)
do i=1 To a.0
say a.i
End
Return

wordsort: Procedure
/**********************************************************************
* Sort the list of words supplied as argument. Return the sorted list
**********************************************************************/
Parse Arg wl
wa.=''
wa.0=0
Do While wl<>''
Parse Var wl w wl
Do i=1 To wa.0
If wa.i>w Then Leave
End
If i<=wa.0 Then Do
Do j=wa.0 To i By -1
ii=j+1
wa.ii=wa.j
End
End
wa.i=w
wa.0=wa.0+1
End
swl=''
Do i=1 To wa.0
swl=swl wa.i
End
Return strip(swl)</syntaxhighlight>
{{out|output|text=&nbsp; when using the default list:}}
<pre>
<pre>
K:\>rexx sso
element 1 before sort: UK London
element 2 before sort: US New York
before sort
UK London
element 3 before sort: US Birmingham
US New York
element 4 before sort: UK Birmingham
US Birmingham
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
element 1 after sort: UK Birmingham
UK Birmingham

element 2 after sort: UK London
sorted by country
element 3 after sort: US Birmingham
UK London
element 4 after sort: US New York
UK Birmingham
US New York
US Birmingham

sorted by city
US Birmingham
UK Birmingham
UK London
US New York
</pre>
</pre>


=={{header|Ring}}==
=={{header|Ring}}==
<lang ring>
<syntaxhighlight lang="ring">
aList = [["UK", "London"],
aList = [["UK", "London"],
["US", "New York"],
["US", "New York"],
Line 1,169: Line 1,644:
["UK", "Birmingham"]]
["UK", "Birmingham"]]
see sort(aList,2)
see sort(aList,2)
</syntaxhighlight>
</lang>


=={{header|Ruby}}==
=={{header|Ruby}}==
Line 1,175: Line 1,650:


{{works with|MRI|1.8.7, 1.9.2}}
{{works with|MRI|1.8.7, 1.9.2}}
<lang ruby>ary = [["UK", "London"],
<syntaxhighlight lang="ruby">ary = [["UK", "London"],
["US", "New York"],
["US", "New York"],
["US", "Birmingham"],
["US", "Birmingham"],
Line 1,181: Line 1,656:
p ary.sort {|a,b| a[1] <=> b[1]}
p ary.sort {|a,b| a[1] <=> b[1]}
# MRI reverses the Birminghams:
# MRI reverses the Birminghams:
# => [["UK", "Birmingham"], ["US", "Birmingham"], ["UK", "London"], ["US", "New York"]]</lang>
# => [["UK", "Birmingham"], ["US", "Birmingham"], ["UK", "London"], ["US", "New York"]]</syntaxhighlight>


Other implementations of Ruby might differ. Old versions of [[JRuby]] used java.util.Arrays.sort, which was a stable sort, but was slower than MRI. To increase performance, JRuby switched to quicksort, which is not stable. [http://jira.codehaus.org/browse/JRUBY-2198 (3)]
Other implementations of Ruby might differ. Old versions of [[JRuby]] used java.util.Arrays.sort, which was a stable sort, but was slower than MRI. To increase performance, JRuby switched to quicksort, which is not stable. [http://jira.codehaus.org/browse/JRUBY-2198 (3)]
Line 1,188: Line 1,663:
To code a stable sort, without implementing another sorting algorithm (such as [[Sorting algorithms/Merge sort|merge sort]]), use a Schwartzian transform.
To code a stable sort, without implementing another sorting algorithm (such as [[Sorting algorithms/Merge sort|merge sort]]), use a Schwartzian transform.


<lang ruby>class Array
<syntaxhighlight lang="ruby">class Array
def stable_sort
def stable_sort
n = -1
n = -1
Line 1,207: Line 1,682:
sort_by {|x| n += 1; [(yield x), n]}
sort_by {|x| n += 1; [(yield x), n]}
end
end
end</lang>
end</syntaxhighlight>


<lang ruby>ary = [["UK", "London"],
<syntaxhighlight lang="ruby">ary = [["UK", "London"],
["US", "New York"],
["US", "New York"],
["US", "Birmingham"],
["US", "Birmingham"],
Line 1,216: Line 1,691:
# => [["US", "Birmingham"], ["UK", "Birmingham"], ["UK", "London"], ["US", "New York"]]
# => [["US", "Birmingham"], ["UK", "Birmingham"], ["UK", "London"], ["US", "New York"]]
p ary.stable_sort_by {|x| x[1]}
p ary.stable_sort_by {|x| x[1]}
# => [["US", "Birmingham"], ["UK", "Birmingham"], ["UK", "London"], ["US", "New York"]]</lang>
# => [["US", "Birmingham"], ["UK", "Birmingham"], ["UK", "London"], ["US", "New York"]]</syntaxhighlight>


=={{header|Rust}}==
=={{header|Rust}}==
Rust's builtin sorts (.sort(), .sort_by(...), .sort_by_key(...)) are all stable
Rust's builtin sorts (.sort(), .sort_by(...), .sort_by_key(...)) are all stable


<lang rust>fn main() {
<syntaxhighlight lang="rust">fn main() {
let country_city = [
let country_city = [
("UK", "London"),
("UK", "London"),
Line 1,249: Line 1,724:
println!("{} {}", x.0, x.1);
println!("{} {}", x.0, x.1);
}
}
}</lang>
}</syntaxhighlight>


Output: <pre>Original:
Output: <pre>Original:
Line 1,277: Line 1,752:


Examples:
Examples:
<lang scala>scala> val list = List((1, 'c'), (1, 'b'), (2, 'a'))
<syntaxhighlight lang="scala">scala> val list = List((1, 'c'), (1, 'b'), (2, 'a'))
list: List[(Int, Char)] = List((1,c), (1,b), (2,a))
list: List[(Int, Char)] = List((1,c), (1,b), (2,a))


Line 1,295: Line 1,770:


scala> cities.sortBy(_ substring 4)
scala> cities.sortBy(_ substring 4)
res47: Seq[String] = ArrayBuffer(US Birmingham, UK Birmingham, UK London, US New York)</lang>
res47: Seq[String] = ArrayBuffer(US Birmingham, UK Birmingham, UK London, US New York)</syntaxhighlight>
Besides that, there is the object <tt>scala.util.Sorting</tt>, which provides <tt>quickSort<tt> and <tt>stableSort</tt>. The former is only provided on <tt>Array</tt>, but the latter is provided over both <tt>Array</tt> and <tt>Seq</tt>. These sorts operate in-place, with the one over <tt>Seq</tt> returning a sorted <tt>Array</tt>. Here is one example:
Besides that, there is the object <tt>scala.util.Sorting</tt>, which provides <tt>quickSort</tt> and <tt>stableSort</tt>. The former is only provided on <tt>Array</tt>, but the latter is provided over both <tt>Array</tt> and <tt>Seq</tt>. These sorts operate in-place, with the one over <tt>Seq</tt> returning a sorted <tt>Array</tt>. Here is one example:
<lang scala>scala> val cityArray = cities.toArray
<syntaxhighlight lang="scala">scala> val cityArray = cities.toArray
cityArray: Array[String] = Array(UK London, US New York, US Birmingham, UK Birmingham)
cityArray: Array[String] = Array(UK London, US New York, US Birmingham, UK Birmingham)


Line 1,303: Line 1,778:


scala> cityArray
scala> cityArray
res56: Array[String] = Array(US Birmingham, UK Birmingham, UK London, US New York)</lang>
res56: Array[String] = Array(US Birmingham, UK Birmingham, UK London, US New York)</syntaxhighlight>


=={{header|Sidef}}==
=={{header|Sidef}}==
Sidef uses the stable merge-sort algorithm for sorting an array.
Sidef uses the stable merge-sort algorithm for sorting an array.
<lang ruby>var table = [
<syntaxhighlight lang="ruby">var table = [
<UK London>,
<UK London>,
<US New\ York>,
<US New\ York>,
Line 1,316: Line 1,791:
table.sort {|a,b| a[0] <=> b[0]}.each { |col|
table.sort {|a,b| a[0] <=> b[0]}.each { |col|
say "#{col[0]} #{col[1]}"
say "#{col[0]} #{col[1]}"
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>UK London
<pre>UK London
Line 1,331: Line 1,806:
=={{header|TXR}}==
=={{header|TXR}}==


TXR provides a number of sorting functions. <code>sort</code> and <code>nsort</code> (destructive variant) are not stable for vectors and strings, but are stable for lists.
Straight from the TXR documentation about the <code>sort</code> function:


The functions <code>ssort</code> and <code>snsort</code> counterparts are stable for all sequence kinds.
<i>The <code>sort</code> function is stable for sequences which are lists. This means that the original order of items which are considered identical is preserved. For strings and vectors, <code>sort</code> is not stable.</i>

In addition, there are caching variants of all these functions: <code>csort</code>, <code>cnsort</code>, <code>cssort</code> and <code>csnsort</code>. They respectively have the same stability properties as their counterparts without the leading <code>c</code>.

TXR Lisp originally had one sorting function called <code>sort</code>, which was destructive, like the <code>sort</code> in Common Lisp. That function was renamed to <code>nsort</code>, and <code>sort</code> became the name of a non-destructive function. That happened in TXR 238, released in May, 2020.


=={{header|Wren}}==
=={{header|Wren}}==
Line 1,340: Line 1,819:


Below we illustrate the points made in the task description using the stable insertion sort.
Below we illustrate the points made in the task description using the stable insertion sort.
<lang ecmascript>import "/sort" for Cmp, Sort
<syntaxhighlight lang="wren">import "./sort" for Cmp, Sort


var data = [ ["UK", "London"], ["US", "New York"], ["US", "Birmingham"], ["UK", "Birmingham"] ]
var data = [ ["UK", "London"], ["US", "New York"], ["US", "Birmingham"], ["UK", "Birmingham"] ]
Line 1,361: Line 1,840:
var data3 = data.toList
var data3 = data.toList
Sort.insertion(data3, cmp2)
Sort.insertion(data3, cmp2)
System.print(" " + data3.join("\n "))</lang>
System.print(" " + data3.join("\n "))</syntaxhighlight>


{{out}}
{{out}}
Line 1,383: Line 1,862:
[US, New York]
[US, New York]
</pre>
</pre>

=={{header|XPL0}}==
There is no built-in sort routine in XPL0. The 32-bit versions are
distributed with xpllib, which provides an integer sort routine. This
uses the Quicksort algorithm, which is unstable.


=={{header|zkl}}==
=={{header|zkl}}==
zkl's sort methods don't mention stability or columns, they are comparison based.
zkl's sort methods don't mention stability or columns, they are comparison based.
<lang zkl>fcn sortByColumn(list,col)
<syntaxhighlight lang="zkl">fcn sortByColumn(list,col)
{ list.sort('wrap(city1,city2){ city1[col]<city2[col] }) }</lang>
{ list.sort('wrap(city1,city2){ city1[col]<city2[col] }) }</syntaxhighlight>
<lang zkl>cities:=List(
<syntaxhighlight lang="zkl">cities:=List(
T("UK", "London"), T("US", "New York"),
T("UK", "London"), T("US", "New York"),
T("US", "Birmingham"),T("UK", "Birmingham"), );
T("US", "Birmingham"),T("UK", "Birmingham"), );
sortByColumn(cities,0).concat("\n").println("\n------");
sortByColumn(cities,0).concat("\n").println("\n------");
sortByColumn(cities,1).concat("\n").println();</lang>
sortByColumn(cities,1).concat("\n").println();</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>

Latest revision as of 17:49, 4 April 2024

Task
Sort stability
You are encouraged to solve this task according to the task description, using any language you may know.

When sorting records in a table by a particular column or field, a stable sort will always retain the relative order of records that have the same key.


Example

In this table of countries and cities, a stable sort on the second column, the cities, would keep the   US Birmingham   above the   UK Birmingham.

(Although an unstable sort might, in this case, place the   US Birmingham   above the   UK Birmingham,   a stable sort routine would guarantee it).

UK  London
US  New York
US  Birmingham
UK  Birmingham

Similarly, stable sorting on just the first column would generate UK London as the first item and US Birmingham as the last item   (since the order of the elements having the same first word –   UK or US   – would be maintained).


Task
  1.   Examine the documentation on any in-built sort routines supplied by a language.
  2.   Indicate if an in-built routine is supplied
  3.   If supplied, indicate whether or not the in-built routine is stable.


(This Wikipedia table shows the stability of some common sort routines).

11l

11l's in-built sorted function as well as the sort method of arrays are not guaranteed stable.

AArch64 Assembly

Works with: as version Raspberry Pi 3B version Buster 64 bits
/* ARM assembly AARCH64 Raspberry PI 3B */
/*  program stableSort641.s   */
 
 /* use merge sort and pointer table  */
 /* but use a extra table of pointer for the merge */
/*******************************************/
/* 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_country:                          // 
    .struct  city_country + 8          // string pointer
city_end:
 
/*********************************/
/* Initialized data              */
/*********************************/
.data
sMessResult:        .asciz "Name : @  country : @ \n"
szMessSortName:     .asciz "Sort table for name of city :\n"
szMessSortCountry:  .asciz "Sort table for country : \n"
szCarriageReturn:   .asciz "\n"

// cities name
szLondon:           .asciz "London"
szNewyork:          .asciz "New York"
szBirmin:           .asciz "Birmingham"
szParis:            .asciz "Paris"
// country name
szUK:               .asciz "UK"
szUS:               .asciz "US"
szFR:               .asciz "FR"
.align 4
TableCities:               
e1:              .quad szLondon         // address name string
                 .quad szUK             // address country string
e2:              .quad szParis
                 .quad szFR
e3:              .quad szNewyork
                 .quad szUS
e4:              .quad szBirmin
                 .quad szUK
e5:              .quad szParis
                 .quad szUS
e6:              .quad szBirmin
                 .quad szUS
/* pointers table */
ptrTableCities:   .quad e1
                  .quad e2
                  .quad e3
                  .quad e4
                  .quad e5
                  .quad e6
.equ NBELEMENTS,  (. - ptrTableCities) / 8
 
/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
sZoneConv:              .skip 24
ptrTableExtraSort:      .skip 8 * NBELEMENTS
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main 
main:                             // entry of program 
    ldr x0,qAdrptrTableCities     // address pointers table
    bl displayTable

    ldr x0,qAdrszMessSortName
    bl affichageMess

    ldr x0,qAdrptrTableCities     // address pointers table
    mov x1,0                      // not use in routine
    mov x2,NBELEMENTS - 1         // number of élements 
    mov x3,#city_name             // sort by city name
    mov x4,#'A'                   // alphanumeric
    ldr x5,qAdrptrTableExtraSort
    bl mergeSort
    ldr x0,qAdrptrTableCities     // address table
    bl displayTable
    
    ldr x0,qAdrszMessSortCountry
    bl affichageMess

    ldr x0,qAdrptrTableCities     // address table
    mov x1,0                      // not use in routine
    mov x2,NBELEMENTS - 1         // number of élements 
    mov x3,#city_country          // sort by city country
    mov x4,#'A'                   // alphanumeric
    ldr x5,qAdrptrTableExtraSort
    bl mergeSort
    ldr x0,qAdrptrTableCities     // 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
qAdrszMessSortName:        .quad szMessSortName
qAdrptrTableExtraSort:     .quad ptrTableExtraSort
qAdrszMessSortCountry:     .quad szMessSortCountry
qAdrptrTableCities:        .quad ptrTableCities
/******************************************************************/
/*      merge sort                                                */ 
/******************************************************************/
/* x0 contains the address of table */
/* x1 contains the index of first element */
/* x2 contains the number of element */
/* x3 contains the offset of area sort */
/* x4 contains the type of area sort N numeric A alpha */
/* x5 contains address extra area */
mergeSort:
    stp x3,lr,[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
    mov x6,x1              // save index first element
    mov x7,x2              // save number of element
    mov x11,x0             // save address table 
    cmp x2,x1              // end ?
    ble 100f
    add x9,x2,x1
    lsr x9,x9,1            // number of element of each subset
    mov x2,x9
    bl mergeSort
    mov x1,x9              // restaur number of element of each subset
    add x1,x1,1
    mov x2,x7              // restaur  number of element
    bl mergeSort           // sort first subset
    add x10,x9,1
1:
    sub x1,x10,1
    sub x8,x10,1
    ldr x2,[x0,x1,lsl 3]
    str x2,[x5,x8,lsl 3]
    sub x10,x10,1
    cmp x10,x6
    bgt 1b
    mov x10,x9
2:
    add x1,x10,1
    add x8,x7,x9
    sub x8,x8,x10
    ldr x2,[x0,x1,lsl 3]
    str x2,[x5,x8,lsl 3]
    add x10,x10,1
    cmp x10,x7
    blt 2b

    mov x10,x6            //k
    mov x1,x6             // i
    mov x2,x7             // j
3:
    mov x0,x5             // table address x1 = i x2 = j x3 = area sort offeset
    bl comparArea
    cmp x0,0
    bgt 5f
    blt 4f
                          // if equal and  i < pivot 
    cmp x1,x9
    ble 4f                // inverse to stable
    b 5f
4:                        // store element subset 1
    mov x0,x5
    ldr x6,[x5,x1, lsl 3]
    str x6,[x11,x10, lsl 3]
    add x1,x1,1
    b 6f
5:                        // store element subset 2
    mov x0,x5
    ldr x6,[x5,x2, lsl 3]
    str x6,[x11,x10, lsl 3]
    sub x2,x2,1
6:
    add x10,x10,1
    cmp x10,x7
    ble 3b
    mov x0,x11

100:
    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 x3,lr,[sp],16     // restaur  2 registers
    ret                   // return to address lr x30
/******************************************************************/
/*      comparison sort area                                */ 
/******************************************************************/
/* x0 contains the address of table */
/* x1 indice area sort 1 */
/* x2 indice area sort 2 */
/* x3 contains the offset of area sort */
/* x4 contains the type of area sort N numeric A alpha */
comparArea:
    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
    
    ldr x1,[x0,x1,lsl 3]         // load pointer element 1
    ldr x6,[x1,x3]               // load area sort element 1
    ldr x2,[x0,x2,lsl 3]         // load pointer element 2
    ldr x7,[x2,x3]               // load area sort element 2
    cmp x4,'A'                   // numeric or alpha ?
    beq 1f
    cmp x6,x7                    // compare numeric value
    blt 10f
    bgt 11f
    b 12f
1:                               // else compar alpha string
    mov x8,#0
2:
    ldrb w9,[x6,x8]              // byte string 1
    ldrb w5,[x7,x8]              // byte string 2
    cmp w9,w5
    bgt 11f                     
    blt 10f

    cmp w9,#0                    //  end string 1
    beq 12f                      // end comparaison
    add x8,x8,#1                 // else add 1 in counter
    b 2b                         // and loop
    
10:                              // lower
    mov x0,-1
    b 100f
11:                              // highter
    mov x0,1
    b 100f
12:                              // equal
    mov x0,0
100:
    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

/******************************************************************/
/*      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
1:                               // loop display table
    lsl x4,x3,#3                 // offset element
    ldr x6,[x2,x4]               // load pointer
    ldr x1,[x6,city_name]
    ldr x0,qAdrsMessResult
    bl strInsertAtCharInc        // put name in message
    ldr x1,[x6,city_country]     // and put country in the message
    bl strInsertAtCharInc        // insert result at @ character
    bl affichageMess             // display message
    add x3,x3,1
    cmp x3,#NBELEMENTS
    blt 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"
Name : London  country : UK
Name : Paris  country : FR
Name : New York  country : US
Name : Birmingham  country : UK
Name : Paris  country : US
Name : Birmingham  country : US

Sort table for name of city :
Name : Birmingham  country : UK
Name : Birmingham  country : US
Name : London  country : UK
Name : New York  country : US
Name : Paris  country : FR
Name : Paris  country : US

Sort table for country :
Name : Paris  country : FR
Name : Birmingham  country : UK
Name : London  country : UK
Name : Birmingham  country : US
Name : New York  country : US
Name : Paris  country : US

Ada

Ada 83 and Ada 95 do not provide a standard sort utility.

Ada 2005 provides two generic procedures for sorting arrays. One (Ada.Containers.Generic_Array_Sort) is for unconstrained array types and one (Ada.Containers.Generic_Constrained_Array_Sort) is for constrained array types. Both are not guaranteed stable and in all implementation they are not.

Also, Vectors and Doubly_Linked_Lists containers have their own internal generic sort. Doubly_Linked_Lists sort is stable.

AppleScript

The AppleScript language doesn't have a built-in sort facility, but there are various possibilities depending on exactly what it is that needs to be sorted:

1. A scripted application may possibly have a sort command in its AppleScript dictionary whose invocation causes it to sort its own data internally (by its own criteria) and/or return them to the script in sorted form.

2. A sort routine written natively in AppleScript can be used as a library. This will be for sorting AppleScript lists, so if the data to be sorted aren't already in the form of a list, they have to be converted first and possibly converted back afterwards. An example of a stable, customisable AS sort is here.

3. The Foundation framework's NSArray and NSMutableArray classes have sorting methods which appear to be stable. However, as with AppleScript sorts, the data have to be converted first if they're not in the form of one of these classes. Furthermore, the methods usable through AppleScriptObjC only sort on named keys, not on positions, so to sort on the "second column" requires the preparation of an array containing objects which each contain an identifiable key matched with a second-column value.

4. If the data are in the form of a single piece of text, AppleScript can pass this to the 'sort' executable which comes with the Bash shell.

The task description doesn't specify what form the "table" takes, but here it's assumed to be a tab-delimited text.

set aTable to "UK	London
US	New York
US	Birmingham
UK	Birmingham"

-- -s = stable sort; -t sets the field separator, -k sets the sort "column" range in field numbers.
set stableSortedOnColumn2 to (do shell script ("sort -st'" & tab & "' -k2,2 <<<" & quoted form of aTable))
set stableSortedOnColumn1 to (do shell script ("sort -st'" & tab & "' -k1,1 <<<" & quoted form of aTable))
return "Stable sorted on column 2:" & (linefeed & stableSortedOnColumn2) & (linefeed & linefeed & ¬
    "Stable sorted on column 1:") & (linefeed & stableSortedOnColumn1)
Output:
"Stable sorted on column 2:
US	Birmingham
UK	Birmingham
UK	London
US	New York

Stable sorted on column 1:
UK	London
UK	Birmingham
US	New York
US	Birmingham"

Arturo

records: @[
    #[country: "UK", city: "London"]
    #[country: "US", city: "New York"]
    #[country: "US", city: "Birmingham"]
    #[country: "UK", city: "Birmingham"]
]

print "Original order:"
loop records => print

print "\nSorted by country name:"
loop sort.by:'country records => print

print "\nSorted by city name:"
loop sort.by:'city records => print
Output:
Original order:
[country:UK city:London]
[country:US city:New York]
[country:US city:Birmingham]
[country:UK city:Birmingham]

Sorted by country name:
[country:UK city:London]
[country:UK city:Birmingham]
[country:US city:New York]
[country:US city:Birmingham]

Sorted by city name:
[country:US city:Birmingham]
[country:UK city:Birmingham]
[country:UK city:London]
[country:US city:New York]

AutoHotkey

Autohotkey has got a build-in sorting method for tables, which is stable.

Table =
(
UK, London
US, New York
US, Birmingham
UK, Birmingham
)

Gui, Margin, 6
Gui, -MinimizeBox
Gui, Add, ListView, r5 w260 Grid, Orig.Position|Country|City
Loop, Parse, Table, `n, `r
{
    StringSplit, out, A_LoopField, `,, %A_Space%
    LV_Add("", A_Index, out1, out2)
}
LV_ModifyCol(1, "77 Center")
LV_ModifyCol(2, "100 Center")
LV_ModifyCol(3, 79)
Gui, Add, Button, w80, Restore Order
Gui, Add, Button, x+10 wp, Sort Countries
Gui, Add, Button, x+10 wp, Sort Cities
Gui, Show,, Sort stability
Return

GuiClose:
GuiEscape:
ExitApp

ButtonRestoreOrder:
    LV_ModifyCol(1, "Sort")
Return

ButtonSortCountries:
    LV_ModifyCol(2, "Sort")
Return

ButtonSortCities:
    LV_ModifyCol(3, "Sort")
Return

AWK

# syntax: GAWK -f SORT_STABILITY.AWK [-v width=x] -v field=x SORT_STABILITY.TXT
#
# sort by country: GAWK -f SORT_STABILITY.AWK -v field=1 SORT_STABILITY.TXT
# sort by city:    GAWK -f SORT_STABILITY.AWK -v field=2 SORT_STABILITY.TXT
#
# awk sort is not stable. Stability may be achieved by appending the
# record number, I.E. NR, to each key.
#
BEGIN {
    FIELDWIDTHS = "4 20" # 2 fields: country city
    PROCINFO["sorted_in"] = "@ind_str_asc"
    if (width == "") {
      width = 6
    }
}
{ arr[$field sprintf("%0*d",width,NR)] = $0 }
END {
    if (length(NR) > width) {
      printf("error: sort may still be unstable; change width to %d\n",length(NR))
      exit(1)
    }
    printf("after sorting on field %d:\n",field)
    for (i in arr) {
      printf("%s\n",arr[i])
    }
    exit(0)
}

input:

UK  London
US  New York
US  Birmingham
UK  Birmingham

output from: GAWK -f SORT_STABILITY.AWK -v field=1 SORT_STABILITY.TXT

after sorting on field 1:
UK  London
UK  Birmingham
US  New York
US  Birmingham

output from: GAWK -f SORT_STABILITY.AWK -v field=2 SORT_STABILITY.TXT

after sorting on field 2:
US  Birmingham
UK  Birmingham
UK  London
US  New York

BBC BASIC

The supplied SORTLIB library currently uses a Shell Sort, so it is not stable.

C

There is no built-in function in C language. stdlib which comes with any C implementation is required to provide a qsort() routine that can sort arbitrary datatypes. Although the sorting algorithm is not specified, most (all?) implementions use a combined quicksort/insertion sort method for efficiency. Quicksort is by nature unstable.

C#

The .NET library documentation for Array.Sort() says that it uses quicksort and is unstable.[1]

C++

C++ standard library's std::sort() function is not guaranteed stable. The stable analog of it is the std::stable_sort() function. In addition, std::list's sort() method is guaranteed stable.

Clojure

Clojure's sort and sort-by functions are implemented using Java's java.utils.Array.sort methods, which are guaranteed stable.

COBOL

The SORT statement causes a set of records or table elements to be arranged in a user-specified sequence.

If the DUPLICATES phrase is specified and the contents of all the key data items associated with one record or table element are equal to the contents of the corresponding key data items associated with one or more other records or table elements, the order of return of these records or the relative order of the contents of these table elements is:

a) The order of the associated input files as specified in the SORT statement. Within a given input file the order is that in which the records are accessed from that file.

b) The order in which these records are released by an input procedure, when an input procedure is specified.

c) The relative order of the contents of these table elements before sorting takes place.

When the DUPLICATES phrase is used, the sort is stable.

Common Lisp

Common Lisp provides the two functions sort and stable-sort.

Each of these functions can sort arbitrary objects using a given predicate function, the input to which can be altered by the optional key parameter.

(eg; sorting file names based upon file sizes, the predicate might be < and the key could be a function that transforms the file's name into its size)

D

In the std.algorithm Phobos v.2 module there is SwapStrategy that defines the swapping strategy for algorithms like sort and partition.

Unstable, stable and semistable (in algorithms that partition ranges in two, semistable preserves stability on just the left of the partition point) are supported.

Déjà Vu

The included sorting algorithm, sort, is stable.

Elixir

Enum.sort and Enum.sort_by of Elixir are stable. These functions use merge sort algorithm. The sorting algorithm will be stable as long as the given function returns true for values considered equal:

cities = [ {"UK", "London"},
           {"US", "New York"},
           {"US", "Birmingham"},
           {"UK", "Birmingham"} ]

IO.inspect Enum.sort(cities)
IO.inspect Enum.sort(cities, fn a,b -> elem(a,0) >= elem(b,0) end)
IO.inspect Enum.sort_by(cities, fn {country, _city} -> country end)
IO.inspect Enum.sort_by(cities, fn {_country, city} -> city end)
Output:
[{"UK", "Birmingham"}, {"UK", "London"}, {"US", "Birmingham"}, {"US", "New York"}]
[{"US", "New York"}, {"US", "Birmingham"}, {"UK", "London"}, {"UK", "Birmingham"}]
[{"UK", "London"}, {"UK", "Birmingham"}, {"US", "New York"}, {"US", "Birmingham"}]
[{"US", "Birmingham"}, {"UK", "Birmingham"}, {"UK", "London"}, {"US", "New York"}]

Note: If the function does not return true, the sorting is not stable and the order of equal terms may be shuffled:

IO.inspect Enum.sort(cities, fn a,b -> elem(a,0) > elem(b,0) end)
Output:
[{"US", "Birmingham"}, {"US", "New York"}, {"UK", "Birmingham"}, {"UK", "London"}]

Erlang

The function lists:sort/1 is not documented as stable. The function lists:keysort/2 is documented as stable.

F#

Array.sort is not stable. List.sort and Seq.sort are stable.

Factor

The sorting vocabulary implements a stable sort. sorting docs

Fortran

The language does not offer an in-built sort facility. Numerous libraries exist, which may or may not have documentation on their sort routine's stability.

FreeBASIC

The language does not offer an in-built sort facility. Numerous libraries exist, which may or may not have documentation on their sort routine's stability.

GAP

# According to section 21.18 of the reference manual, Sort is not stable (it's a Shell sort).
# However, SortingPerm is stable. We will see it on an example, showing indexes of elements after the sort.

n := 20;
L := List([1 .. n], i -> Random("AB"));
# "AABABBBABBABAABABBAB"


p := SortingPerm(L);
# (3,10,15,17,18,19,9,14,7,13,6,12,16,8,4)(5,11)

a := Permuted(L, p);;
b := Permuted([1 .. n], p);;

PrintArray(TransposedMat(List([1 .. n], i -> [a[i], b[i]])));
# [ [  'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',  'A',  'B',  'B',  'B',  'B',  'B',  'B',  'B',  'B',  'B',  'B',  'B' ],
#   [    1,    2,    4,    8,   11,   13,   14,   16,   19,    3,    5,    6,    7,    9,   10,   12,   15,   17,   18,   20 ] ]

Go

New to Go 1.2 is the function Stable() in the sort package and is documented to be a stable sort. Other sort functions are documented to have no guarantee of stability.

Groovy

Groovy's Collection.sort(), Object[].sort(), Map.sort(), and their various and sundry overloads all use the same stable sort algorithm.

Example:

Translation of: Java
Works with: Groovy version 1.8.1
def cityList = ['UK  London', 'US  New York', 'US  Birmingham', 'UK  Birmingham',].asImmutable()
[
    'Sort by city': { city -> city[4..-1] },
    'Sort by country': { city -> city[0..3] },
].each{ String label, Closure orderBy ->
    println "\n\nBefore ${label}"
    cityList.each { println it }
    println "\nAfter ${label}"
    cityList.sort(false, orderBy).each{ println it }
}

Output:

Before Sort by city
UK  London
US  New York
US  Birmingham
UK  Birmingham

After Sort by city
US  Birmingham
UK  Birmingham
UK  London
US  New York


Before Sort by country
UK  London
US  New York
US  Birmingham
UK  Birmingham

After Sort by country
UK  London
UK  Birmingham
US  New York
US  Birmingham

Haskell

Haskell's sort and sortBy functions are guaranteed stable.[2]

Icon and Unicon

Icon and Unicon use Quick Sort internally. As described in The Implementation of Icon and Unicon: a Compendium] sorting is done by the standard C library routine qsort which is not guaranteed to be stable.

Note(1): The built-in sort handles lists of mixed types by sorting first by type and then value. No coercion of types is performed. The sort order of types is: &null, integer, real, string, cset, procedure, list, set, table, record.

J

J's grade primitive /:, and therefore its sort (such as /:~), are guaranteed stable.

From the dictionary page for /: : "Elements of /:y that select equal elements of y are in ascending order."

Java

Java's Collections.sort() and Arrays.sort() methods are guaranteed stable.

The following sample demonstrates Java's sort stability:

import java.util.Arrays;
import java.util.Comparator;

public class RJSortStability {

  public static void main(String[] args) {
    String[] cityList = { "UK  London", "US  New York", "US  Birmingham", "UK  Birmingham", };

    String[] cn = cityList.clone();
    System.out.println("\nBefore sort:");
    for (String city : cn) {
      System.out.println(city);
    }

    // sort by city
    Arrays.sort(cn, new Comparator<String>() {
      public int compare(String lft, String rgt) {
        return lft.substring(4).compareTo(rgt.substring(4));
      }
    });

    System.out.println("\nAfter sort on city:");
    for (String city : cn) {
      System.out.println(city);
    }

    cn = cityList.clone();
    System.out.println("\nBefore sort:");
    for (String city : cn) {
      System.out.println(city);
    }

    // sort by country
    Arrays.sort(cn, new Comparator<String>() {
      public int compare(String lft, String rgt) {
        return lft.substring(0, 2).compareTo(rgt.substring(0, 2));
      }
    });

    System.out.println("\nAfter sort on country:");
    for (String city : cn) {
      System.out.println(city);
    }

    System.out.println();
  }
}
Output
Before sort:
UK  London
US  New York
US  Birmingham
UK  Birmingham

After sort on city:
US  Birmingham
UK  Birmingham
UK  London
US  New York

Before sort:
UK  London
US  New York
US  Birmingham
UK  Birmingham

After sort on country:
UK  London
UK  Birmingham
US  New York
US  Birmingham

JavaScript

The ECMAScript 2019 standard defines Array.sort() as stable.

At the time of writing this is already implemented in in Node.js and in the JS interpreters of all major browsers, including Microsoft Edge, but not according to the Mozilla implementations table, the older Internet Explorer. In earlier interpreters, sort stability depends on particular implementations.

ary = [["UK", "London"], ["US", "New York"], ["US", "Birmingham"], ["UK", "Birmingham"]]
print(ary);

ary.sort(function(a,b){return (a[1]<b[1] ? -1 : (a[1]>b[1] ? 1 : 0))});
print(ary);

/* a stable sort will output ["US", "Birmingham"] before ["UK", "Birmingham"] */

Stable implementations:

Works with: SpiderMonkey version 1.8
Works with: Firefox version 3
Works with: Internet Explorer version 6
Works with: JScript version 5.7
Works with: OSSP js
UK,London,US,New York,US,Birmingham,UK,Birmingham
US,Birmingham,UK,Birmingham,UK,London,US,New York

Not stable:

Works with: Rhino version 1.7 rel 2
Works with: Google Chrome version 3.0
UK,London,US,New York,US,Birmingham,UK,Birmingham
UK,Birmingham,US,Birmingham,UK,London,US,New York

jq

As of January 18, 2016 (Commit SHA 7835a72), the builtin sorting filters (notably sort/0 and sort_by/1) are stable; prior to that, stability was platform-dependent. This means that stability is NOT guaranteed in jq 1.5 or earlier. In the following, a version of jq with sorting stability has been used.

[["UK", "London"],
 ["US", "New York"],
 ["US", "Birmingham"],
 ["UK", "Birmingham"]]
| sort_by(.[1])

Invocation:

$ jq -c -n -f rc-sort-stability.jq
Output:
[["US","Birmingham"],["UK","Birmingham"],["UK","London"],["US","New York"]]

Julia

Julia's built-in sort function is documented to be stable by default (although non-stable sort algorithms can optionally be selected).

julia> A = [("UK", "London"), ("US", "New York"), ("US", "Birmingham"), ("UK", "Birmingham")];
julia> sort(A, by=x -> x[2])
4-element Array{(ASCIIString,ASCIIString),1}:
 ("US","Birmingham")
 ("UK","Birmingham")
 ("UK","London")    
 ("US","New York") 

Kotlin

The collections in Kotlin's standard library are thin wrappers around the corresponding JDK collections and, since the latter's sort methods are stable, so too are Kotlin's standard sort functions.

// version 1.1.51

fun main(args: Array<String>) {
    val cities = listOf("UK London", "US New York", "US Birmingham", "UK Birmingham")
    println("Original   : $cities")
    // sort by country
    println("By country : ${cities.sortedBy { it.take(2) } }")
    // sort by city
    println("By city    : ${cities.sortedBy { it.drop(3) } }")
}
Output:
Original   : [UK London, US New York, US Birmingham, UK Birmingham]
By country : [UK London, UK Birmingham, US New York, US Birmingham]
By city    : [US Birmingham, UK Birmingham, UK London, US New York]

Lasso

Arrays can be sorted in two “built in" ways in Lasso:

//Single param array:
array->sort

//An array of pairs, order by the right hand element of the pair: 
with i in array order by #i->second do => {  }

//The array can also be ordered by multiple values:
with i in array order by #i->second, #i->first do => {  }

Sorting of arrays by either method uses “Qucksort” and is therefore unstable. A simulation of increasing sort stability would be introduced with additional params such as the example of ordering by the second then the first pair values in the example above - but would not be guaranteed stable.

  • Note this explanation of sorting does not cover ordering by properties of complex objects, which is also possible using query expressions.

Sort by second value only:

local(a = array('UK'='London','US'='New York','US'='Birmingham','UK'='Birmingham'))
with i in #a order by #i->second do => {^ #i->first+' - '+#i->second+'\r' ^}
Output:
US - Birmingham
UK - Birmingham
UK - London
US - New York

Sort by second then by first:

local(a = array('UK'='London','US'='New York','US'='Birmingham','UK'='Birmingham'))
with i in #a order by #i->second, #i->first do => {^ #i->first+' - '+#i->second+'\r' ^}
Output:
UK - Birmingham
US - Birmingham
UK - London
US - New York

Liberty BASIC

LB has build-in SORT routine. Documentation does not says if it's stable or not. Example from RC keeps order.

Here's an example showing that SORT indeed unstable.

randomize 0.5
N=15
dim a(N,2)

for i = 0 to N-1
    a(i,1)= int(i/5)
    a(i,2)= int(rnd(1)*5)
next

print "Unsorted by column #2"
print "by construction sorted by column #1"
for i = 0 to N-1
    print a(i,1), a(i,2)
next

sort a(), 0, N-1, 2
print

print "After sorting by column #2"
print "Notice wrong order by column #1"
for i = 0 to N-1
    print a(i,1), a(i,2),
    if i=0 then
        print
    else
        if  a(i,2) = a(i-1,2) AND  a(i,1) < a(i-1,1) then print "bad order" else print
    end if
next
Output:
Unsorted by column #2
by construction sorted by column #1
0             4
0             1
0             1
0             0
0             4
1             1
1             1
1             2
1             1
1             0
2             4
2             3
2             2
2             0
2             4

After sorting by column #2
Notice wrong order by column #1
0             0
1             0
2             0
1             1
1             1
1             1
0             1             bad order
0             1
1             2
2             2
2             3
2             4
0             4             bad order
0             4
2             4

Lua

The built-in function table.sort is not guaranteed stable.

M2000 Interpreter

M2000 has two types of Inventories, objects using a hash algorithm, the normal with unique keys, so a sort statement on this object use quicksort, and a second type, the "queue" type, which can get same keys, and has stable sort.

Here is the stable sort

Module Stable {
      Inventory queue alfa 
      Stack New {
            Data "UK", "London","US", "New York","US", "Birmingham", "UK","Birmingham"
            While not empty {
                  Append alfa, Letter$:=letter$
            }
      }
      sort alfa
      k=Each(alfa)
      Document A$
      NL$={
      }
      While k {
            A$= Eval$(k, k^)+" "+eval$(k)+NL$
      }
      Clipboard A$ ' write to clipboard
      Report A$
}
Call Stable

Output:
UK London
UK Birmingham
US New York
US Birmingham


We can sort in on key only. Lets make keys with two fields (based on fields lengths, except for last one)

Module Stable1 {
      Inventory queue alfa 
      Stack New {
            Data "UK London","US New York","US Birmingham", "UK Birmingham"
            While not empty {
                  Append alfa, Letter$
            }
      }
      sort alfa
      k=Each(alfa)
      Document A$
      NL$={
      }
      While k {
            A$= Eval$(k, k^)+NL$
      }
      Clipboard A$ ' write to clipboard
      Report A$
}
Call Stable1

Output:
UK Birmingham
UK London
US Birmingham
US New York

Now second column is sorting (but it is one column all, no two columns). So lets see the unstable sort. Because all keys now are unique we just remove queue from Inventory definition.

Module Stable2 {
      Inventory alfa 
      Stack New {
            Data "UK London","US New York","US Birmingham", "UK Birmingham"
            While not empty {
                  Append alfa, Letter$
            }
      }
      sort alfa
      k=Each(alfa)
      Document A$
      NL$={
      }
      While k {
            A$= Eval$(k, k^)+NL$
      }
      Clipboard A$ ' write to clipboard
      Report A$
}
Call Stable2

Output:
UK Birmingham
UK London
US Birmingham
US New York

So now we see that using unique keys in either type of inventories we get same output. By default in inventory queue numbers in keys (in any position) are sorted as numbers. We can use sort alfa as number for normal inventory, or sort alfa as text

For ascending/descending sort we can use sort descending alfa as number

If we delete a key in normal inventory we miss the sort order. We can't delete keys in queue inventories, but we can drop from the last append a number of keys. Also Exist() function in queue inventories always find the last entry (for same keys), until that dropped, so with next use of Exist(pointer_to_inventory, key_case_sensitive$) we find the previous one. We can use keys as numbers, but they stored as strings.

Mathematica/Wolfram Language

Sort is not always stable. Ordering, which gives a list of indices such as to put the elements of the list in order, is stable. An example would be to sort the list (of lists) {{1, 2, 3}, {4, 5, 6}, {5, 4, 3}, {9, 5, 1}}, and doing so by looking at the 2nd value of each list:

mylist = {{1, 2, 3}, {4, 5, 6}, {5, 4, 3}, {9, 5, 1}};
Sort[mylist, (#1[[2]] < #2[[2]]) &]
#[[Ordering[#[[All, 2]]]]] &[mylist]

gives:

{{1, 2, 3}, {5, 4, 3}, {9, 5, 1}, {4, 5, 6}}
{{1, 2, 3}, {5, 4, 3}, {4, 5, 6}, {9, 5, 1}}

Showing that Sort is unstable, and that by using input[[Ordering[input]]] Ordering provides a way to make a stable sort.

MATLAB

MathWorks' policy seems to be that their built-in sorting algorithm will always be a stable sort across all versions (reference). To check to see if your version of MATLAB provides a stable sort,check the output of command "help sort".

NetRexx

Java's Collections.sort() and Arrays.sort() methods are guaranteed stable. The following sample takes advantage of this to demonstrate sort stability.

/* NetRexx */
options replace format comments java crossref savelog symbols nobinary

class RCSortStability

method main(args = String[]) public constant

  cityList = [String "UK  London", "US  New York", "US  Birmingham", "UK  Birmingham"]

  cn = String[cityList.length]

  say
  say "Before sort:"
  System.arraycopy(cityList, 0, cn, 0, cityList.length)
  loop city = 0 to cn.length - 1
    say cn[city]
    end city

  cCompNm = Comparator CityComparator()
  Arrays.sort(cn, cCompNm)

  say
  say "After sort on city:"
  loop city = 0 to cn.length - 1
    say cn[city]
    end city

  say
  say "Before sort:"
  System.arraycopy(cityList, 0, cn, 0, cityList.length)
  loop city = 0 to cn.length - 1
    say cn[city]
    end city

  cCompCtry = Comparator CountryComparator()
  Arrays.sort(cn, cCompCtry)

  say
  say "After sort on country:"
  loop city = 0 to cn.length - 1
    say cn[city]
    end city
  say

  return

class RCSortStability.CityComparator implements Comparator

method compare(lft = Object, rgt = Object) public binary returns int
  return (String lft).substring(4).compareTo((String rgt).substring(4))

class RCSortStability.CountryComparator implements Comparator

method compare(lft = Object, rgt = Object) public binary returns int
  return (String lft).substring(0, 2).compareTo((String rgt).substring(0, 2))
Output
Before sort:
UK  London
US  New York
US  Birmingham
UK  Birmingham

After sort on city:
US  Birmingham
UK  Birmingham
UK  London
US  New York

Before sort:
UK  London
US  New York
US  Birmingham
UK  Birmingham

After sort on country:
UK  London
UK  Birmingham
US  New York
US  Birmingham

Nim

Default Nim sort in the algorithm module is stable.

import algorithm

const Records = [(country: "UK", city: "London"),
                 (country: "US", city: "New York"),
                 (country: "US", city: "Birmingham"),
                 (country: "UK", city: "Birmingham")]

echo "Original order:"
for record in Records:
  echo record.country, " ", record.city
echo()

echo "Sorted by city name:"
for record in Records.sortedByIt(it.city):
  echo record.country, " ", record.city
echo()

echo "Sorted by country name:"
for record in Records.sortedByIt(it.country):
  echo record.country, " ", record.city
Output:
Original order:
UK London
US New York
US Birmingham
UK Birmingham

Sorted by city name:
US Birmingham
UK Birmingham
UK London
US New York

Sorted by country name:
UK London
UK Birmingham
US New York
US Birmingham

OCaml

OCaml's List.sort and Array.sort functions are not guaranteed to be stable. The stable versions are List.stable_sort and Array.stable_sort, respectively.

ooRexx

Open Object Rexx provides sort methods (sort and sortWith(comparator)) for its collection classes. By default these sort methods are implemented via an unstable Quicksort algorithm but the language does provide stable sorting methods (stableSort and stableSortWith(comparator)) implemented via a stable Mergesort algorithm.

/* Rexx */
Do
  cities = .array~of('UK  London', 'US  New York', 'US  Birmingham', 'UK  Birmingham',)

  Say; Say 'Original table'
  Call display cities

  Say; Say 'Unstable sort on city'
  sorted = cities~copy
  sorted~sortWith(.ColumnComparator~new(4, 20))
  Call display sorted

  Say; Say 'Stable sort on city'
  sorted = cities~copy
  sorted~stableSortWith(.ColumnComparator~new(4, 20))
  Call display sorted

  Say; Say 'Unstable sort on country'
  sorted = cities~copy
  sorted~sortWith(.ColumnComparator~new(1, 2))
  Call display sorted

  Say; Say 'Stable sort on country'
  sorted = cities~copy
  sorted~stableSortWith(.ColumnComparator~new(1, 2))
  Call display sorted

  Return
End
Exit

display: Procedure
Do
  Use arg CT

  Say '-'~copies(80)
  Loop c_ over CT
    Say c_
    End c_

  Return
End
Exit
Output
Original table
--------------------------------------------------------------------------------
UK  London
US  New York
US  Birmingham
UK  Birmingham

Unstable sort on city
--------------------------------------------------------------------------------
UK  Birmingham
US  Birmingham
UK  London
US  New York

Stable sort on city
--------------------------------------------------------------------------------
US  Birmingham
UK  Birmingham
UK  London
US  New York

Unstable sort on country
--------------------------------------------------------------------------------
UK  London
UK  Birmingham
US  Birmingham
US  New York

Stable sort on country
--------------------------------------------------------------------------------
UK  London
UK  Birmingham
US  New York
US  Birmingham

OpenEdge/Progress

The results can be forced to stable by additionally sorting on the ROWID of the record. If you leave the additional sort out, the indexes on the temp-table can influence the result.

DEFINE TEMP-TABLE tt
   FIELD country  AS CHAR FORMAT 'x(2)'
   FIELD city     AS CHAR FORMAT 'x(16)'
   .

DEFINE VARIABLE cc AS CHARACTER EXTENT 2.

CREATE tt. ASSIGN tt.country = 'UK' tt.city = 'London'.
CREATE tt. ASSIGN tt.country = 'US' tt.city = 'New York'.
CREATE tt. ASSIGN tt.country = 'US' tt.city = 'Birmingham'.
CREATE tt. ASSIGN tt.country = 'UK' tt.city = 'Birmingham'.

cc[1] = 'by country~n~n'.
FOR EACH tt BY tt.country BY ROWID( tt ):
   cc[1] = cc[1] + tt.country + '~t' + tt.city + '~n'.
END.

cc[2] = 'by city~n~n'.
FOR EACH tt BY tt.city BY ROWID( tt ):
   cc[2] = cc[2] + tt.country + '~t' + tt.city + '~n'.
END.

MESSAGE
   cc[1] SKIP(1) cc[2]
VIEW-AS ALERT-BOX.

Output:

---------------------------
Message
---------------------------
by country

UK	London
UK	Birmingham
US	New York
US	Birmingham


by city

US	Birmingham
UK	Birmingham
UK	London
US	New York
---------------------------
OK   
---------------------------

Oz

Oz' Sort function is not guaranteed to be stable in the documentation.

However, internally it uses Merge sort and in practice is stable if a reflexive ordering is used, e.g. Value.'=<' or Value.'>='.

Example:

declare
  Cities = ['UK'#'London'
            'US'#'New York'
            'US'#'Birmingham'
            'UK'#'Birmingham']
in
  %% sort by city; stable because '=<' is reflexiv
  {Show {Sort Cities fun {$ A B} A.2 =< B.2 end}}

  %% sort by country; NOT stable because '<' is not reflexiv
  {Show {Sort Cities fun {$ A B} A.1 < B.1 end}}

PARI/GP

Pari's vecsort is stable, see 3.8.60 in the User's Guide. In particular, it uses a merge sort.

Pascal

Standard Pascal has no built-in routine for sorting. The RTL of FreePascal uses Quicksort for TList, TFPList and TStringList in the Classes unit. In many places in the standard libraries fgl and in generics.collections the sort is configurable provided the programmer implements a sort.

Perl

The stability of Perl's in-built sort function is version-dependent. If you want to guarantee a stable sort from it, you should use the following sort pragma:

use sort 'stable';

Phix

The standard sort method is merge sort, which is apparently stable, though I would be reluctant to guarantee that, or rely on it, especially given that a simple tag sort is irrefutably stable since it explicitly orders by tag (aka original position) within any equal keys.

with javascript_semantics
sequence test = {{"UK","London"},
                 {"US","New York"},
                 {"US","Birmingham"},
                 {"UK","Birmingham"}}
 
---------------------
-- probably stable --
---------------------
function cmp(object a, object b)
    return compare(a[2],b[2])
end function
pp(custom_sort(cmp,deep_copy(test)),{pp_Nest,1})
 
-----------------------
-- guaranteed stable --
-----------------------
function tag_cmp(integer i, integer j)
    integer c = compare(test[i][2],test[j][2])
    if c=0 then c = compare(i,j) end if -- (see note)
    return c
end function
sequence tags = custom_sort(tag_cmp,shuffle(tagset(4)))
pp(extract(test,tags),{pp_Nest,1})
Output:
{{`US`, `Birmingham`},
 {`UK`, `Birmingham`},
 {`UK`, `London`},
 {`US`, `New York`}}
{{`US`, `Birmingham`},
 {`UK`, `Birmingham`},
 {`UK`, `London`},
 {`US`, `New York`}}

Commenting out the c=0 fixup in tag_cmp makes it unstable, or rather probably stable wrt the shuffle, and sometimes shows the first two lines flipped, whereas the active line guarantees original (pre-shuffle) ordering, even if an unstable underlying sort method were used. Of course test=sort(test) guarantees alphabetical on second column within matching first column. Lastly, preserving a primary tag sort ordering within a secondary tag sort is a bit more mind-bending, but even that is not particularly difficult.

PHP

PHP uses QuickSort for most of its sort functions so it is unstable. [3]

PicoLisp

The sort function is unstable

PureBasic

PureBasic's includes two built-in sort functions for arrays, SortArray() and SortStructuredArray(), and two built-in sort functions for linked lists, SortList() and SortStructuredList(). Sorting of linked lists is stable and uses a merge-sort, while sorting for arrays is unstable and uses a quicksort.

Python

Python's in-built sorted function as well as the sort method of lists are guaranteed stable (since version 2.3). (For even more information on the underlying routine, wp:timsort, see this).


Quackery

The inbuilt sort is stable.

R

R uses shell sort (stable) or quick sort (unstable). An easy way to show the difference is names to vector entries, then check if names are still ordered after sorting.

# First, define a bernoulli sample, of length 26.
x <- sample(c(0, 1), 26, replace=T)

x
# [1] 1 1 1 1 0 1 1 0 1 0 1 1 1 0 1 1 0 1 0 1 0 1 1 0 1 0

# Give names to the entries. "letters" is a builtin value
names(x) <- letters

x
# a b c d e f g h i j k l m n o p q r s t u v w x y z
# 1 1 1 1 0 1 1 0 1 0 1 1 1 0 1 1 0 1 0 1 0 1 1 0 1 0

# The unstable one, see how "a" appears after "l" now
sort(x, method="quick")
# z h s u e q x n j r t v w y p o m l a i g f d c b k
# 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

# The stable sort, letters are ordered in each section
sort(x, method="shell")
# e h j n q s u x z a b c d f g i k l m o p r t v w y
# 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

Racket

Racket comes with a standard sort function, which is documented [here]. It is documented as stable.

#lang racket

(sort '(("UK" "London")
        ("US" "New York")
        ("US" "Birmingham")
        ("UK" "Birmingham"))
      string<? #:key first)
;; -> (("UK" "London") ("UK" "Birmingham")
;;     ("US" "New York") ("US" "Birmingham"))

(sort '(("UK" "London")
        ("US" "New York")
        ("US" "Birmingham")
        ("UK" "Birmingham"))
      string<? #:key second)
;; -> '(("US" "Birmingham") ("UK" "Birmingham")
;;      ("UK" "London") ("US" "New York"))

Raku

(formerly Perl 6)

The sort built-in (available as sub and method) is stable.

Short demonstration for sorting only on the second item of each array:

use v6;
my @cities =
    ['UK', 'London'],
    ['US', 'New York'],
    ['US', 'Birmingham'],
    ['UK', 'Birmingham'],
    ;

.say for @cities.sort: { .[1] };

REBOL

; REBOL's sort function is not stable by default. You need to use a custom comparator to make it so.

blk: [
    [UK London]
    [US New-York]
    [US Birmingham]
    [UK Birmingham]
]
sort/compare blk func [a b] [either a/2 < b/2 [-1] [either a/2 > b/2 [1] [0]]]

; Note that you can also do a stable sort without nested blocks.
blk: [
    UK London
    US New-York
    US Birmingham
    UK Birmingham
]
sort/skip/compare blk 2 func [a b] [either a < b [-1] [either a > b [1] [0]]]

REXX

/*REXX program sorts a (stemmed) array */ /* replacing the wrong program published here earlier */ call gena /*generate the array elements (strings)*/ call show 'before sort' /*show the before array elements. */ call stableSort exit /*----------------------------------------------------------------------------*/ stableSort: procedure expose a.

 parse Value  With l1 l2
 Do i=1 To a.0
   parse Var a.i f1 f2
   f2=translate(f2,'_',' ')
   If pos(f1,l1)=0 Then l1=l1 f1
   If pos(f2,l2)=0 Then l2=l2 f2
   End
 l1=wordsort(l1)
 l2=wordsort(l2)
 Say 
 Say 'sorted by country'
 Do While l1<>
   Parse Var l1 f1s l1
   Do i=1 To a.0
     parse Var a.i f1 f2
     If f1=f1s Then
       Say a.i
     End
   End
 Say 
 Say 'sorted by city'
 Do While l2<>
   Parse Var l2 f2s l2
   Do i=1 To a.0
     parse Var a.i f1 f2
     If translate(f2,'_',' ')=f2s Then
       Say a.i
     End
   End

/*---------------------------------------------------------------------------------*/ gena: a.0=0

 Call store 'UK  London'
 Call store 'US  New York'
 Call store 'US  Birmingham'
 Call store 'UK  Birmingham'
 Return

store:

 z=a.0+1
 a.z=arg(1)
 a.0=z
 Return

show:

 Say arg(1)
 do i=1 To a.0
 say a.i
 End
 Return

wordsort: Procedure /**********************************************************************

  • Sort the list of words supplied as argument. Return the sorted list
                                                                                                                                            • /
 Parse Arg wl
 wa.=
 wa.0=0
 Do While wl<>
   Parse Var wl w wl
   Do i=1 To wa.0
     If wa.i>w Then Leave
     End
   If i<=wa.0 Then Do
     Do j=wa.0 To i By -1
       ii=j+1
       wa.ii=wa.j
       End
     End
   wa.i=w
   wa.0=wa.0+1
   End
 swl=
 Do i=1 To wa.0
   swl=swl wa.i
   End
 Return strip(swl)</syntaxhighlight>
output   when using the default list:
K:\>rexx sso
before sort
UK  London
US  New York
US  Birmingham
UK  Birmingham

sorted by country
UK  London
UK  Birmingham
US  New York
US  Birmingham

sorted by city
US  Birmingham
UK  Birmingham
UK  London
US  New York

Ring

aList = [["UK", "London"],
        ["US", "New York"],
        ["US", "Birmingham"],
        ["UK", "Birmingham"]]
see sort(aList,2)

Ruby

Ruby's built-in sort methods (Array#sort, Array#sort!, Array#sort_by!, Enumerable#sort and Enumerable#sort_by) are not stable. MRI uses quicksort, which is not stable (1). It seems that stable sorting is not worth the performance trade-off; MRI rejected a proposal to switch to a stable sort (2).

Works with: MRI version 1.8.7, 1.9.2
ary = [["UK", "London"],
       ["US", "New York"],
       ["US", "Birmingham"],
       ["UK", "Birmingham"]]
p ary.sort {|a,b| a[1] <=> b[1]}
# MRI reverses the Birminghams:
# => [["UK", "Birmingham"], ["US", "Birmingham"], ["UK", "London"], ["US", "New York"]]

Other implementations of Ruby might differ. Old versions of JRuby used java.util.Arrays.sort, which was a stable sort, but was slower than MRI. To increase performance, JRuby switched to quicksort, which is not stable. (3)

Stable sort in Ruby

To code a stable sort, without implementing another sorting algorithm (such as merge sort), use a Schwartzian transform.

class Array
  def stable_sort
    n = -1
    if block_given?
      collect {|x| n += 1; [x, n]
      }.sort! {|a, b|
        c = yield a[0], b[0]
        if c.nonzero? then c else a[1] <=> b[1] end
      }.collect! {|x| x[0]}
    else
      sort_by {|x| n += 1; [x, n]}
    end
  end

  def stable_sort_by
    block_given? or return enum_for(:stable_sort_by)
    n = -1
    sort_by {|x| n += 1; [(yield x), n]}
  end
end
ary = [["UK", "London"],
       ["US", "New York"],
       ["US", "Birmingham"],
       ["UK", "Birmingham"]]
p ary.stable_sort {|a, b| a[1] <=> b[1]}
# => [["US", "Birmingham"], ["UK", "Birmingham"], ["UK", "London"], ["US", "New York"]]
p ary.stable_sort_by {|x| x[1]}
# => [["US", "Birmingham"], ["UK", "Birmingham"], ["UK", "London"], ["US", "New York"]]

Rust

Rust's builtin sorts (.sort(), .sort_by(...), .sort_by_key(...)) are all stable

fn main() {
    let country_city = [
        ("UK", "London"),
        ("US", "New York"),
        ("US", "Birmingham"),
        ("UK", "Birmingham"),
    ];

    let mut city_sorted = country_city.clone();
    city_sorted.sort_by_key(|k| k.1);

    let mut country_sorted = country_city.clone();
    country_sorted.sort_by_key(|k| k.0);

    println!("Original:");
    for x in &country_city {
        println!("{} {}", x.0, x.1);
    }

    println!("\nWhen sorted by city:");
    for x in &city_sorted {
        println!("{} {}", x.0, x.1);
    }

    println!("\nWhen sorted by county:");
    for x in &country_sorted {
        println!("{} {}", x.0, x.1);
    }
}

Output:

Original:
UK London
US New York
US Birmingham
UK Birmingham

When sorted by city:
US Birmingham
UK Birmingham
UK London
US New York

When sorted by county:
UK London
UK Birmingham
US New York
US Birmingham

Scala

Works with: Scala version 2.8

There are two sort methods defined on Seq, which is the base collection trait for all sequences. The methods are sortWith and sortBy, and differ only on the argument used. The first expects a function that will implement the "less than" method for the type of the sequence. The second expects a function from the type of the sequence into any type for which there is an Ordering, plus an implicit Ordering of the proper type.

The sort is stable.

Examples:

scala> val list = List((1, 'c'), (1, 'b'), (2, 'a'))
list: List[(Int, Char)] = List((1,c), (1,b), (2,a))

scala> val srt1 = list.sortWith(_._2 < _._2)
srt1: List[(Int, Char)] = List((2,a), (1,b), (1,c))

scala> val srt2 = srt1.sortBy(_._1) // Ordering[Int] is implicitly defined
srt2: List[(Int, Char)] = List((1,b), (1,c), (2,a))

scala> val cities = """
     | |UK  London
     | |US  New York
     | |US  Birmingham
     | |UK  Birmingham
     | |""".stripMargin.lines.filterNot(_ isEmpty).toSeq
cities: Seq[String] = ArrayBuffer(UK  London, US  New York, US  Birmingham, UK  Birmingham)

scala> cities.sortBy(_ substring 4)
res47: Seq[String] = ArrayBuffer(US  Birmingham, UK  Birmingham, UK  London, US  New York)

Besides that, there is the object scala.util.Sorting, which provides quickSort and stableSort. The former is only provided on Array, but the latter is provided over both Array and Seq. These sorts operate in-place, with the one over Seq returning a sorted Array. Here is one example:

scala> val cityArray = cities.toArray
cityArray: Array[String] = Array(UK  London, US  New York, US  Birmingham, UK  Birmingham)

scala> scala.util.Sorting.stableSort(cityArray, (_: String).substring(4) < (_: String).substring(4))

scala> cityArray
res56: Array[String] = Array(US  Birmingham, UK  Birmingham, UK  London, US  New York)

Sidef

Sidef uses the stable merge-sort algorithm for sorting an array.

var table = [
  <UK  London>,
  <US  New\ York>,
  <US  Birmingham>,
  <UK  Birmingham>,
];

table.sort {|a,b| a[0] <=> b[0]}.each { |col|
    say "#{col[0]} #{col[1]}"
}
Output:
UK London
UK Birmingham
US New York
US Birmingham

Stata

See sort in Stata help. The command has a stable option to ensure sort stability.

Tcl

Tcl's built-in lsort command implements a stable sort. It has been guaranteed to be stable since Tcl 8.0. Internally, it uses the mergesort algorithm.

TXR

TXR provides a number of sorting functions. sort and nsort (destructive variant) are not stable for vectors and strings, but are stable for lists.

The functions ssort and snsort counterparts are stable for all sequence kinds.

In addition, there are caching variants of all these functions: csort, cnsort, cssort and csnsort. They respectively have the same stability properties as their counterparts without the leading c.

TXR Lisp originally had one sorting function called sort, which was destructive, like the sort in Common Lisp. That function was renamed to nsort, and sort became the name of a non-destructive function. That happened in TXR 238, released in May, 2020.

Wren

Library: Wren-sort

Of the six sorting algorithms supported by the above module, two (merge and insertion) are stable and the other four (quick, heap, selection and shell) are unstable.

Below we illustrate the points made in the task description using the stable insertion sort.

import "./sort" for Cmp, Sort

var data = [ ["UK", "London"], ["US", "New York"], ["US", "Birmingham"], ["UK", "Birmingham"] ]

// for sorting by country
var cmp = Fn.new { |p1, p2| Cmp.string.call(p1[0], p2[0]) }

// for sorting by city
var cmp2 = Fn.new { |p1, p2| Cmp.string.call(p1[1], p2[1]) }

System.print("Initial data:")
System.print("  " + data.join("\n  "))

System.print("\nSorted by country:")
var data2 = data.toList
Sort.insertion(data2, cmp)
System.print("  " + data2.join("\n  "))

System.print("\nSorted by city:")
var data3 = data.toList
Sort.insertion(data3, cmp2)
System.print("  " + data3.join("\n  "))
Output:
Initial data:
  [UK, London]
  [US, New York]
  [US, Birmingham]
  [UK, Birmingham]

Sorted by country:
  [UK, London]
  [UK, Birmingham]
  [US, New York]
  [US, Birmingham]

Sorted by city:
  [US, Birmingham]
  [UK, Birmingham]
  [UK, London]
  [US, New York]

XPL0

There is no built-in sort routine in XPL0. The 32-bit versions are distributed with xpllib, which provides an integer sort routine. This uses the Quicksort algorithm, which is unstable.

zkl

zkl's sort methods don't mention stability or columns, they are comparison based.

fcn sortByColumn(list,col)
   { list.sort('wrap(city1,city2){ city1[col]<city2[col] }) }
cities:=List(
   T("UK",  "London"), T("US",  "New York"), 
   T("US",  "Birmingham"),T("UK",  "Birmingham"), );
sortByColumn(cities,0).concat("\n").println("\n------");
sortByColumn(cities,1).concat("\n").println();
Output:
L("UK","London")
L("UK","Birmingham")
L("US","New York")
L("US","Birmingham")
------
L("UK","Birmingham")
L("US","Birmingham")
L("UK","London")
L("US","New York")