Sort a list by its second items

I have a list of items that must to be sorted by their second arguments:


set k to {{"Extra Suites", "2.4"}, {"Microsoft Entourage", "1.8"}, {"Safari", "1.3"}, {"Dock", "0.9"}, {"DragThing", "0.3"}, {"lazymousebg", "0.2"},  {"Script Editor", "3.1"}, {"Keychain Scripting", "0.0"}, {"Finder", "0.0"}}

Is there a way to accomplish that…?

A simple bubblesort routine can do this for you:

set k to {{"Extra Suites", "2.4"}, {"Microsoft Entourage", "1.8"}, {"Safari", "1.3"}, {"Dock", "0.9"}, {"DragThing", "0.3"}, {"lazymousebg", "0.2"}, {"Script Editor", "3.1"}, {"Keychain Scripting", "0.0"}, {"Finder", "0.0"}}
bubblesort(k)
on bubblesort(array)
	repeat with i from length of array to 2 by -1 --> go backwards
		repeat with j from 1 to i - 1 --> go forwards
			tell array
				if (item j)'s item 2 > (item (j + 1))'s item 2 then
					set {item j, item (j + 1)} to {item (j + 1), item j} -- swap
				end if
			end tell
		end repeat
	end repeat
	return array
end bubblesort

-->{{"Keychain Scripting", "0.0"}, {"Finder", "0.0"}, {"lazymousebg", "0.2"}, {"DragThing", "0.3"}, {"Dock", "0.9"}, {"Safari", "1.3"}, {"Microsoft Entourage", "1.8"}, {"Extra Suites", "2.4"}, {"Script Editor", "3.1"}}

Good luck, hope this helps.

I see Craig beat me to it with a much simpler approach. This one just bends a script I use for other purposes to this question.

I use the handler below to keep multiple lists in register while sorting on one of them:


to sort_items(sortList, SecondList, thirdList) -- a variation of and additions to a script by Kai
	tell (count sortList) to repeat with i from (it - 1) to 1 by -1
		set s to sortList's item i
		set r to SecondList's item i
		set q to thirdList's item i
		repeat with i from (i + 1) to it
			tell sortList's item i to if s > it then
				set sortList's item (i - 1) to it
				set SecondList's item (i - 1) to SecondList's item i
				set thirdList's item (i - 1) to thirdList's item i
			else
				set sortList's item (i - 1) to s
				set SecondList's item (i - 1) to r
				set thirdList's item (i - 1) to q
				exit repeat
			end if
		end repeat
		if it is i and s > sortList's end then
			set sortList's item it to s
			set SecondList's item it to r
			set thirdList's item it to q
		end if
	end repeat
end sort_items

To use it, you’d have to pull the items you want to sort by into a separate list:


set k to {{"Extra Suites", "2.4"}, {"Microsoft Entourage", "1.8"}, {"Safari", "1.3"}, {"Dock", "0.9"}, {"DragThing", "0.3"}, {"lazymousebg", "0.2"}, {"Script Editor", "3.1"}, {"Keychain Scripting", "0.0"}, {"Finder", "0.0"}}

set L to {}
repeat with j from 1 to count k
	set end of L to item 2 of item j of k
end repeat

set Sorted to sort_items(L, k)
--> {{"Keychain Scripting", "0.0"}, {"Finder", "0.0"}, {"lazymousebg", "0.2"}, {"DragThing", "0.3"}, {"Dock", "0.9"}, {"Safari", "1.3"}, {"Microsoft Entourage", "1.8"}, {"Extra Suites", "2.4"}, {"Script Editor", "3.1"}}

to sort_items(sortList, SecondList) --, thirdList)
	tell (count sortList) to repeat with i from (it - 1) to 1 by -1
		set s to sortList's item i
		set r to SecondList's item i
		--set q to thirdList's item i
		repeat with i from (i + 1) to it
			tell sortList's item i to if s > it then
				set sortList's item (i - 1) to it
				set SecondList's item (i - 1) to SecondList's item i
				--set thirdList's item (i - 1) to thirdList's item i
			else
				set sortList's item (i - 1) to s
				set SecondList's item (i - 1) to r
				--set thirdList's item (i - 1) to q
				exit repeat
			end if
		end repeat
		if it is i and s > sortList's end then
			set sortList's item it to s
			set SecondList's item it to r
			--set thirdList's item it to q
		end if
	end repeat
	return SecondList
end sort_items

— EDITED to return a result per Nigel’s post below — :rolleyes:

Hi.

Just to point out (if it’s important) that those textual numbers are sorted lexically rather than numerically. It shouldn’t make any difference as long as they’re all below “10”.

Both Craig’s and Adam’s handlers sort k directly. Adam’s handler doesn’t explicitly return a result, so Sorted shouldn’t be set to the result of it. It’s interesting that there’s no error when the variable’s set to a non-result “ only when there’s a subsequent attempt to use the variable!

I suppose “ just for completeness, you understand :rolleyes: “ that I should point out the CustomQsort() handler described here. One of the customising script objects I’ve given with it sorts a list of lists by indexed items in them. However, I suspect it’s overkill for Eelco’s purposes. :wink:

Thanks for that reminder, Nigel. The following script should take care of things, and sort the second items as numbers, in case you are still interested in using the bubble sort routine:

set k to {{"Extra Suites", "2.4"}, {"Microsoft Entourage", "1.8"}, {"Safari", "1.3"}, {"Dock", "0.9"}, {"DragThing", "0.3"}, {"lazymousebg", "0.2"}, {"Script Editor", "3.1"}, {"Keychain Scripting", "0.0"}, {"Finder", "0.0"}, {"Finder", "10.10"}, {"Finder", "100.04"}, {"Finder", "100.01"}}
bubblesort(k)
on bubblesort(array)
	repeat with i from length of array to 2 by -1 --> go backwards
		repeat with j from 1 to i - 1 --> go forwards
			tell array
				if ((item j)'s item 2 as number) > ((item (j + 1))'s item 2 as number) then
					set {item j, item (j + 1)} to {item (j + 1), item j} -- swap
				end if
			end tell
		end repeat
	end repeat
	return array
end bubblesort

-->{{"Keychain Scripting", "0.0"}, {"Finder", "0.0"}, {"lazymousebg", "0.2"}, {"DragThing", "0.3"}, {"Dock", "0.9"}, {"Safari", "1.3"}, {"Microsoft Entourage", "1.8"}, {"Extra Suites", "2.4"}, {"Script Editor", "3.1"}, {"Finder", "10.10"}, {"Finder", "100.01"}, {"Finder", "100.04"}}

Hi, Craig.

I remembered this morning that, as from AppleScript 1.10, there’s a new considering/ignoring attribute for string comparisons: numeric strings. Your original handler code (if it’s only to be run in Tiger or later) could be enclosed in a considering numeric strings block:

set k to {{"Extra Suites", "2.4"}, {"Microsoft Entourage", "1.8"}, {"Safari", "1.3"}, {"Dock", "0.9"}, {"DragThing", "0.3"}, {"lazymousebg", "0.2"}, {"Script Editor", "3.1"}, {"Keychain Scripting", "0.0"}, {"Finder", "0.0"}, {"Finder", "10.10"}, {"Finder", "100.04"}, {"Finder", "100.01"}}
bubblesort(k)
on bubblesort(array)
	considering numeric strings
		repeat with i from length of array to 2 by -1 --> go backwards
			repeat with j from 1 to i - 1 --> go forwards
				tell array
					if (item j)'s item 2 > (item (j + 1))'s item 2 then
						set {item j, item (j + 1)} to {item (j + 1), item j} -- swap
					end if
				end tell
			end repeat
		end repeat
	end considering
	return array
end bubblesort

-->{{"Keychain Scripting", "0.0"}, {"Finder", "0.0"}, {"lazymousebg", "0.2"}, {"DragThing", "0.3"}, {"Dock", "0.9"}, {"Safari", "1.3"}, {"Microsoft Entourage", "1.8"}, {"Extra Suites", "2.4"}, {"Script Editor", "3.1"}, {"Finder", "10.10"}, {"Finder", "100.01"}, {"Finder", "100.04"}}

This seems to be marginally faster (with the test list) than individual coercions to number. It also, of course, removes the necessity for the second item in each list to be coercible to number. But as I said, it’s only available with Tiger so far. Minutely faster still is considering case and numeric strings!

In theory, for greater flexibility, the considering block could enclose the call to the handler rather than being in the handler itself. That way, the same handler could used to sort either considering or ignoring numeric strings. I can’t imagine that would be particularly useful here, though. :slight_smile:

Perhaps not here, but it would never have occurred to me to enclose a handler call in a ‘considering’ block instead of putting the ‘considering’ in the handler and passing the consideration as an argument. Neat this way because it means a generic sorter can become useful for sorting numbers, ASCII, pay attention to capitalization or not, etc. Very nice indeed. Chalk up another Garvey lesson learned! :lol: I knew you could do that with text item delimiters, but not with considerations.

Add my wholehearted praise to that! This is super duper! Thank you very much, Nigel, you just gave us a couple of new tools!

Thanks all.
Very clever use of the considering statement, Nigel.
It handles the sorting > 1 well, but its speed increase (running the routine for 5000 times) can’t be noticed here on my Intel MacBook.

(For the record: the numbers were real-life load percentages (Unix TOP command), Finder figures > 100 NOT !)