A Quicksort handler with labeled property on which sort is done passed as a parameter (Thanks to Nigel Garvey for inspiration). Highly reusable code! Works more efficiently than BubbleSort, even more on long lists (less than 1/4 second for a list of 1000 records on a 2008 MacBook Pro, about 4.5 seconds for 10,000).Can also sort on descending order (reverse sort). Need Yosemite or later to compile the GetTick script.
on QuickSortLR(aList, Le, Ri, compObj) --> QuickSort for a list of records, based on original Tony Hoare quicksort 1959
script Sal --> script object aList
property Liszt : aList
end script
set {I, J} to {Le, Ri}
set Piv to item ((Le + Ri) div 2) of Sal's Liszt --> pivot is choosen in the middle
repeat while J > I
repeat while compObj's isSmaller(item I of Sal's Liszt, Piv)
set I to I + 1
end repeat
repeat while compObj's isLarger(item J of Sal's Liszt, Piv)
set J to J - 1
end repeat
if not I > J then
tell (a reference to Sal's Liszt) to set {item I, item J} to {item J, item I} --> let's swap (waltz for 2!)
set {I, J} to {I + 1, J - 1}
end if
end repeat
if Le < J then QuickSortLR(Sal's Liszt, Le, J, compObj)
if Ri > I then QuickSortLR(Sal's Liszt, I, Ri, compObj)
end QuickSortLR
script byNickName --> one script needed for every labeled property on which sort is required
on isLarger(x, y)
(x's NickName > y's NickName)
end isLarger
on isSmaller(x, y)
(x's NickName < y's NickName)
end isSmaller
end script
script byAge --> one script needed for every labeled property on which sort is required
on isLarger(x, y)
x's Age > y's Age
end isLarger
on isSmaller(x, y)
x's Age < y's Age
end isSmaller
end script
set HowMany to 1000
set StartTick to GetTick's Now()
set MyList to MakeList(HowMany)
set MakeTime to (GetTick's Now()) - StartTick
set StartTick to GetTick's Now()
QuickSortLR(MyList, 1, HowMany, byNickName)
set QsTime to (GetTick's Now()) - StartTick
{MyList, MakeTime, QsTime} --> results
on MakeList(HowMany)
set MyList to {}
set UpCaseConsons to {"B", "C", "D", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "V", "W", "X", "Y", "Z"}
set LoCaseVoyels to {"a", "e", "i", "o", "u"}
set LoCaseLetters to {"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"}
repeat with I from 1 to HowMany
set the end of MyList to {NickName:item (random number from 1 to 21) of UpCaseConsons & ¬
item (random number from 1 to 5) of LoCaseVoyels & ¬
item (random number from 1 to 26) of LoCaseLetters, Age:random number from 1 to 100}
end repeat
return MyList
end MakeList
script GetTick --> for more precise timer calculations
use framework "Foundation"
on Now()
return (current application's NSDate's timeIntervalSinceReferenceDate) as real
end Now
end script
→ results
→ few records shown here (byByAge)
→ {{{NickName:“Yew”, Age:1}, {NickName:“Nas”, Age:1}, .{NickName:“Dap”, Age:39}, {NickName:“Hut”, Age:39},.{NickName:“Yik”, Age:100}, {NickName:“Zan”, Age:100}, {NickName:“Ruk”, Age:100}, {NickName:“Ded”, Age:100}}, 1.586159050465, 0.225466012955}
→ few records shown here (by NickName)
→ {{{NickName:“Bac”, Age:22}, {NickName:“Bai”, Age:54}, {NickName:“Bap”, Age:79}, {NickName:“Baq”, Age:37}, .{NickName:“Hur”, Age:9}, {NickName:“Hur”, Age:72}, {NickName:“Hus”, Age:10}, {NickName:“Hut”, Age:39}, {NickName:“Huw”, Age:7}, {NickName:“Huy”, Age:69}, .{NickName:“Zur”, Age:66}, {NickName:“Zut”, Age:1}, {NickName:“Zut”, Age:66}}, 1.64743500948, 0.213027954102}
Doing a reverse can be done by an extra compObj in this manner:
script byNickNameReverse --> one script needed for every label on which sort is required
on isLarger(x, y)
(x's NickName < y's NickName)
end isLarger
on isSmaller(x, y)
(x's NickName > y's NickName)
end isSmaller
end script
or by simply reversing the list after sort, AppleScript is very efficient at doing this (0.069 second for 10,000 items):
set MyList to every item of reverse of MyList