Sort Not Working...Please Help...

The AppleScript is as follows:


set testList to {"hname", "jname", "aname", "zname", "yname"}

simple_sort(the testList)

on simple_sort(the my_list)
	set the index_list to {}
	set the sorted_list to {}
	repeat (the number of items in my_list) times
		set the low_item to ""
		repeat with i from 1 to (number of items in my_list)
			if i is not in the index_list then
				set this_item to item i of my_list as text
				if the low_item is "" then
					set the low_item to this_item
					set the low_item_index to i
				else if this_item comes before the low_item then
					set the low_item to this_item
					set the low_item_index to i
				end if
			end if
		end repeat
		set the end of sorted_list to the low_item
		set the end of the index_list to the low_item_index
	end repeat
	return the sorted_list
end simple_sort

The problems I am having are as follows:

  1. The sort is working properly but the sorted list is not being passed back [i.e. within the “on simple_sort” a number of log tests show that the list is being sorted BUT a log test after calling simple_sort shows that the list is not sorted].

  2. Within the “on simple_sort” the list items do appear to be separated by commas when using log commands to log the list during its buildup and sort.

Would appreciate your help in sorting this out.

Thx…

Hey Joel,

You are NOT sorting the list you’re passing as a parameter to your handler. Your handler’s output is sorted_list.

If you want the original list to be sorted then:

set testList to simple_sort(testList)

the is optional, in fact the may be omitted everywhere in your script - unless you need it for clarity.

To be pedantic, the original list is still not sorted here. What Chris’s line does is to reassign the original variable to the new, sorted list returned by JoelC’s handler.

It’s possible to write sorts which do rearrange the items within the original lists. Here’s JoelC’s code with a couple of modifications to make it sort “in place”:


set testList to {"hname", "jname", "aname", "zname", "yname"}

simple_sort(the testList)
return testList --> {"aname", "hname", "jname", "yname", "zname"}

on simple_sort(the sorted_list) -- Here, sorted_list is the *original* list.
	set the index_list to {}
	set my_list to the sorted_list's items -- Here, my_list is a *new* list containing the original items.
	set list_length to (count my_list)
	repeat with j from 1 to list_length -- Use a loop index in this repeat.
		set the low_item to ""
		repeat with i from 1 to list_length
			if i is not in the index_list then
				set this_item to item i of my_list --as text
				if the low_item is "" then
					set the low_item to this_item
					set the low_item_index to i
				else if this_item comes before the low_item then
					set the low_item to this_item
					set the low_item_index to i
				end if
			end if
		end repeat
		set item j of sorted_list to the low_item -- Replace the next item in the original list instead of setting the end of the new one.
		set the end of the index_list to the low_item_index
	end repeat
	-- return the sorted_list -- Optional. It's the original list which has been sorted and this will be apparent when using variable assigned to it outside the handler.
end simple_sort

@Chris, appreciate your help…as I am new to scripting I thought that the code “simple_sort(testList)” would result in the result in both i) the list testList being passed to the handler and sorted and ii) the sorted list being passed back and reassigned to testList…I do take your point that the reassignment will not happen unless I set testList to the returned and sorted list (i.e. simple_sort(testList))…thank you.


@ Nigel, appreciate your help and do take your point that i) Chris’ revisions do not result in the original list being sorted hence the need for the code "set testList to simple_sort(testList) and ii) yoru revision DOES result in the original list being sorted hence no need for “Chris’ reassignment” (though I do need to closely examine your code to fully understand it)…thx.


@ All, one follow up…I want sort a list of lists in the form of {{“htime”, “hname”, “hnumber”}, {“jtime”, “jname”, “jnumber”}, {“atime”,“aname”, “anumber”}, {“ztime”, “zname”, “znumber”], {“ytime”, “yname”.“ynumber”}} by the first item in each sub-list (i.e. time).

When I i) set testList to the above modified list and ii) run the script the list is sorted but the output does not look (i.e. through the use of the log command) right in that:

  1. The log command’s output looks like (atimeanameanumber, htimehnamehnumber,…)

  2. I think that the log command’s output SHOULD look like (atime, aname, anumber, htime, hname, hnumber…)

With that explained:

  1. Is the log command’s output correct; and

  2. If not then what is the fix.

Thanks

Hi JoelC.

This line in your original sort .

set this_item to item i of my_list as text

. is coercing each list in the list to text. You need to cut the ‘as text’ so that this_item remains a list, then change the ‘else’ line four lines later to:

else if item 1 of this_item comes before item 1 of the low_item then

That should do the trick.

Hopefully not to confuse you further: in practice, instead of writing entire sort handlers to sort different kinds of objects, it’s often best to have just one, customisable sort handler and to write short “plug-ins” to do the comparisons. The version below uses a plug-in which compares the first items of the lists in testList:


set testList to {{"htime", "hname", "hnumber"}, {"jtime", "jname", "jnumber"}, {"atime", "aname", "anumber"}, {"ztime", "zname", "znumber"}, {"ytime", "yname", "ynumber"}}

-- This script object's isGreater() handler returns true or false according to whether or not item 1 of 'a' is greater than item 1 of 'b'.
script sortOnFirstItems
	on isGreater(a, b)
		return (item 1 of a > item 1 of b)
	end isGreater
end script

-- Sort testList using sortOnFirstItems to compare the lists in it.
set testList to simple_sort(testList, sortOnFirstItems)

-- This version of the sort delegates the comparison of items in the list to the passed script object's isGreater() handler.
on simple_sort(my_list, comparer)
	set the index_list to {}
	set the sorted_list to {}
	repeat (the number of items in my_list) times
		set the low_item to ""
		repeat with i from 1 to (number of items in my_list)
			if i is not in the index_list then
				set this_item to item i of my_list
				if (the low_item is "") or (comparer's isGreater(the low_item, this_item)) then
					set the low_item to this_item
					set the low_item_index to i
				end if
			end if
		end repeat
		set the end of sorted_list to the low_item
		set the end of the index_list to the low_item_index
	end repeat
	return the sorted_list
end simple_sort

Nigel, appreciate the corrected code and, more importantly the need for it and why it works.

The good news is that I understand [or, at least I think I understand] the concept you are suggesting which is to have a general [i.e. all purpose] sort handler that can compare / work with all data and any “sort item / key” [i.e. the simple_sort handler above] by first writing a small script that compares and passes the “sort item / key” [i.e. the script sortOnFirstItems above which, for greater clarity could / would be modified were I wanting to sort on the second item]. Is my understanding correct?

The bad news is that unlike the changes to my script which I completely understand I am not sure that I understand your above script…that said, is the following understanding correct and, if not, then please clarify it:

  1. The code set testList to simple_sort(testList, sortOnFirstItems) simply sets the list testList to the result of the handler simple_sort(testList,sortOnFirstItems).

  2. The handler simple_sort(my_list, comparer) sorts the list that is passed to it [i.e. testList] based on the comparison criteria [i.e. the first item of each list within the list testList].

  3. The handler simple_sort calls the handler isGreater to ensure that the correct items are compared and returned.

  4. The handler simple_sort then returns the sorted list.

  5. Were I to really want to make the script generic then I would change all instances of “sortOnFirstItems” to something like “sortOnCrtiteria” [note the criteria would be added as a comment] because then the script would be truly generic with the ONLY REQUIRED CHANGE BEING THE LINE OF CODE “return (item 1 of a > item 1 of b)” to ensure that the right comparison is being made. While we are discussing this, for example, if I had just a list of items [i.e. no contained / internal lists] then that line of code would read “return ( a > b)”…Is my understanding correct?

Thanks for all the help [noting I will get there but am still on the steep learning / reading curve!]

Hi JoelC.

You’re understanding’s excellent ” which is gratifying for me, since I’m never sure how well I’m explaining things. :wink:

That’s right. The handler’s based on the one you originally posted rather than my in-place version, although a customisable in-place version is equally possible.

In the context of the script, yes. As you obviously understand from your fifth question, the handler itself simply sorts the items in the list passed to it. The comparisons on which its sorting is based are performed by the isGreater(a, b) handler in the passed script object.

simple_sort calls isGreater with a pair of values from the list it’s sorting (here, two lists from testList). isGreater returns the boolean value ‘true’ if the first value is to be considered greater than the second, and ‘false’ if it isn’t. The criterion here for the first value being considered greater is that its first item has to be greater than the second value’s first item. The simple_sort handler then takes the appropriate sorting action based on whether isGreater tells it ‘true’ or ‘false’.

Yes.

Not quite sure I understand this. While simple_sort itself is generic, the script object(s) passed to it are specific to particular comparison criteria and would ideally have descriptive names. In complex or advanced situations, you might want to use several different script objects to sort by different criteria within the same script. Or you might find it convenient to store such customising script objects as library scripts in their own rights and load them as required. (But this is comparatively advanced stuff. Don’t worry about it now if you’re a beginner!)

The handler in each script object has to have the same name (ie. isGreater) and the same number of parameters (2), but the code within this handler can be as simple or as complex as is required.

Spot on. :slight_smile: Assuming you wanted a straightforward sort, that is. If you wanted a reversed sort, you could use ‘return (a < b)’. This would make simple_sort think the first value was greater than the second only if it were actually less!

Nigel:

A quick note to thank you ever so much for all of our assistance as you [hopefully] got me to where I need to be [or close enough] to do what I need to do and, for this, I am most grateful.

Even though I have decided to learn this on my own as a hobby of sorts, I am convinced and determined that I will get there with assistance and tutoring from helpful people such as yourself.

I will be trying to put this sorting capability to use over the next few days – on limitations are work demands – and will come back to you with results.

Thanks again.

Nigel:

A quick note to let you know that the sorting is well “sorted” in that the I am able to successfully call the sorting script from other scripts and have the proper sorted information / string returned…thank you!

I do however have two other issues with respect to the script I am writing so to the extent you are willing to continue lending a hand please let me know and I will post them for your review.

Joel

That’s the “sort” of thing I like to hear. I’m glad you were able to fix your emergency in the other thread too. That must have been hairy for a while.

If you’ve any further problems, do feel free to post them in new, appropriately titled threads. I can’t guarantee to be able to answer myself, but anyone here with the necessary knowledge, free time, and interest will be happy to help you out. :slight_smile:

Nigel, in case you are interested the URL is http://macscripter.net/viewtopic.php?pid=43337#p43337 .

Thanks for everything.