Sort small list of integers, lowest to highest

I need to sort a list of 4 numbers or less from lowest to highest, then use the sort to re-build a list of corresponding items.

The final result would be

NewItemList : { “File3B”, “FileTM”,“File1”, “FileZ”}

Perl folks have a very simple technique for this called the Schwartzian Transform. Here’s how you do it using AppleMods’ List library:

property _Loader : run application "LoaderServer"


property _List : missing value

on __load__(loader)
	set _List to loader's loadLib("List")
end __load__


__load__(_Loader's makeLoader()) -- load libraries

-- main code

set ItemList to {"File1", "FileZ", "File3B", "FileTM"}
set Cdate to {13, 15, 1, 2}

set lst to _List's recomposeList({Cdate, ItemList})
set lst to _List's sortListOfLists(lst, {1})
set SortedItemList to item 2 of _List's recomposeList(lst)
--> {"File3B", "FileTM", "File1", "FileZ"}

If you’ve not used AppleMods’ libraries before, you’ll need to download and install AppleMods’ Loader system first. Run the Loader installer, then download the List library and add it to the ASLibraries folder. You can use the LoaderWizard applet to generate the library loading code to paste at the top of your script.


Use the Shwartz! I will try that, but I’m still fishing for vanilla AS.

The above script is 100% vanilla AS: none of AppleMods libraries require third-party apps or osaxen. You could roll your own list recomposing and sort routines, of course, but why bother when there’s already good-quality versions freely available for the taking?

If you need your compiled script to be portable across machines then you can bind its dependencies at compile-time by changing:

__load__(_Loader's makeLoader()) -- load libraries at run-time


property _ : __load__(_Loader's makeLoader()) -- load libraries at compile-time

You can even copy-n-paste the relevant library code into your own script if you really want, though it’ll be up to you to ensure you include all the pieces you need and respect the original (very liberal) licence.

As the Perl folks say, Laziness is a Virtue. :slight_smile:



Because I like to take things apart and put them back together. I like to make pizza from scratch. I build my beats off a keyboard. At the same time trying to stay lazy…

I’ve reached a stump in my own sort routines and I’m fishing for a simple pathway I might have overlooked. Right now I’m getting the lowest number in the Cdate list, associating it to the file, and building a new filelist. Then I remove the last low number out of the original Cdate list and again get the lowest value to build sorted list. I’ve got it narrowed down with a few errors, but it’s really pissing me off :lol:

You’ll find that list sorting algorithms are a very well solved problem in computer science - it does have a 50-year headstart, after all - and the best way to start learning is by studying prior art, of which there is no shortage. e.g. See the Dictionary of Algorithms and Data Structures.

Begin with bubble sort; its efficiency is poor, but the algorithm is simple and easy to understand. Then look at the classic quicksort algorithm, which is more than sufficient for most folk, and maybe understand the meaning and implications of ‘in-place sorting’ and ‘stable sorting’.

Beyond that you’re into algorithm guru-only stuff like shellsorts and heapsorts and heavy-duty optimisation tricks for improving performance in special cases like semi-sorted lists. Buy yourself a good algorithms book if you’re really interested in the subject.

Thanks very much. Your right on the money! :wink:

Here is a home-made version (though the question is already covered :wink: )

set ItemList to {"File1", "FileZ", "File3B", "FileTM"}
set Cdate to {13, 15, 1, 2}

sortListOfLists(lazeLists(ItemList, Cdate), 2)

set {ItemList, Cdate} to lazeLists(result, missing value)

to sortListOfLists(lst, fld)
	script a
		property l1 : lst
		property l2 : {l1's item 1}
	end script
	repeat with i from 1 to count lst
		set f to a's l1's item i's item fld
		considering case
			if f < a's l2's item 1's item fld then
				set beginning of a's l2 to a's l1's item i
			else if f > a's l2's item -1's item fld then
				set end of a's l2 to a's l1's item i
			else --> loop
				repeat with x from 1 to count lst
						if f > a's l2's item x's item fld and f < a's l2's item (x + 1)'s item fld then
							set a's l2 to (a's l2's items 1 thru x) & {(a's l1's item i)} & (a's l2's items (x + 1) thru -1)
							exit repeat
						end if
					end try
				end repeat
			end if
		end considering
	end repeat
	return a's l2
end sortListOfLists

to lazeLists(x, y)
	if y is missing value then
		set {n, l} to {{}, {}}
		repeat with i from 1 to count x
			set n's end to x's item i's item 1
			set l's end to x's item i's item 2
		end repeat
		return {n, l}
		set nl to {}
		repeat with i from 1 to count x
			set nl's end to {x's item i, y's item i}
		end repeat
		return nl
	end if
end lazeLists

Thanks JJ, those are the nuts and bolts I was looking for. Thanks again to hhas for reminding me this is a science and should be treated as such.

You wrote a script back in March that employed such a sort. :slight_smile:

However, that’s overkill here. If there really are only four numbers to sort, you can simply cycle through the list four times and find (then eliminate) the smallest number each time. Unless you actually want to use a sorted list of the numbers later on, you can just “sort” the other list:

set ItemList to {"File1", "FileZ", "File3B", "FileTM"}
set Cdate to {13, 15, 1, 2}

set newItemList to {}
-- set newCdate to {}

set tooHigh to 0
repeat 4 times
	set minPos to 1
	set minVal to item minPos of Cdate
	repeat with i from 1 to 4
		if (item i of Cdate < minVal) then
			set minVal to item i of Cdate
			set minPos to i
		else if (item i of Cdate > tooHigh) then
			set tooHigh to (item i of Cdate) + 1
		end if
	end repeat
	set end of newItemList to item minPos of ItemList
	-- set end of newCdate to item minPos of Cdate
	-- Eliminate this number by making it higher than any other found.
	set item minPos of Cdate to tooHigh
end repeat