AppleScript ObjC sorting records using strings and numbers

Hello merry scripters! I found the following script from Shane Stanley’s book “Everyday AppleScriptObjC” which sorts records based on one or more keys. This works well when each key is a string, like sorting a list of last names and first names.


use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

on sortTheList:theList
	set desc1 to current application's NSSortDescriptor's sortDescriptorWithKey:"lastName" ascending:true selector:"localizedCaseInsensitiveCompare:"
	set desc2 to current application's NSSortDescriptor's sortDescriptorWithKey:"firstName" ascending:true selector:"localizedCaseInsensitiveCompare:"
	set theArray to current application's NSArray's arrayWithArray:theList
	return (theArray's sortedArrayUsingDescriptors:{desc1, desc2}) as list
end sortTheList:

set theList to {{firstName:"Jenny", lastName:"Smith"}, {firstName:"Robert", lastName:"Andrews"}, {firstName:"Ann", lastName:"Smith"}, {firstName:"Brian", lastName:"Smith"}, {firstName:"Ann", lastName:"Andrews"}, {firstName:"Gail", lastName:"Frost"}}

its sortTheList:theList

But when I tried sorting a record with keys that are a mix of strings and numbers, I got an error. In the following example I have substituted “age” (an integer) for the second key.


use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

on sortTheList:theList
	set desc1 to current application's NSSortDescriptor's sortDescriptorWithKey:"lastName" ascending:true selector:"localizedCaseInsensitiveCompare:"
	set desc2 to current application's NSSortDescriptor's sortDescriptorWithKey:"age" ascending:true selector:"localizedCaseInsensitiveCompare:"
	set theArray to current application's NSArray's arrayWithArray:theList
	return (theArray's sortedArrayUsingDescriptors:{desc1, desc2}) as list
end sortTheList:

set theList to {{lastName:"Smith", age:21}, {lastName:"Andrews", age:50}, {lastName:"Smith", age:42}, {lastName:"Smith", age:28}, {lastName:"Andrews", age:36}, {lastName:"Frost", age:55}}

its sortTheList:theList

It works OK on the first key but if two of them are the same, it needs to sort using the second key and this gives an error of an unrecognized selector being sent to localizedCaseInsensitiveCompare.

I tried using a selector of “intValue” instead of “localizedCaseInsensitiveCompare” but the script wasn’t having any of that. Is it possible to sort both strings and numbers in AppleScript ObjC?

I believe the compare method works with both numbers and strings. I edited your script to implement this change and to switch the sort descriptors (just for testing), and it seems to work OK:

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

on sortTheList:theList
	set desc2 to current application's NSSortDescriptor's sortDescriptorWithKey:"lastName" ascending:true selector:"localizedCaseInsensitiveCompare:"
	set desc1 to current application's NSSortDescriptor's sortDescriptorWithKey:"age" ascending:true selector:"compare:"
	set theArray to current application's NSArray's arrayWithArray:theList
	return (theArray's sortedArrayUsingDescriptors:{desc1, desc2}) as list
end sortTheList:

set theList to {{lastName:"Smith", age:21}, {lastName:"Andrews", age:50}, {lastName:"Smith", age:42}, {lastName:"Smith", age:28}, {lastName:"Andrews", age:36}, {lastName:"Frost", age:55}}

its sortTheList:theList

Thanks for that peavine, that works a treat.

I don’t know where I would have found that info without asking here. Even the Apple documentation for sortDescriptorWithKey only lists one example of a selector and not all the possible selectors. https://developer.apple.com/documentation/foundation/nssortdescriptor/1503730-sortdescriptorwithkey

I agree that the Apple documentation is not always as helpful as it might be, although there is a logic to it that becomes more evident with time. FWIW, in this particular case I looked at:

  • The NSString and NSNumber documentation under the “Comparing” heading.
  • The localizedStandardCompare documentation under the “See Also” heading.
  • Shane’s discussion of this issue on page 31 of his book.

Thanks again. I just went to page 31 and see I had previously written down in the margin about using ‘compare’ instead of ‘localizedStandardCompare’ for numbers. A long time ago, LOL.