Sorting a list of strings by the length of each item

I have this script that’s not working. The idea is you would select several line in SD, run the script and those lines would be sorted longest to shortest and the sorted text would replace the selection.

It says it doesn’t understand this line:
“set countList to current application’s NSArray’s arrayWithArray:countList”

But if I send it a list like this: {“bb”, “ccc”, “D”, “A”, “aaa”, “aa”, “aaaaa”, “a”}

it works.

Any suggestions?

use AppleScript
use framework "Foundation"
use scripting additions

tell application "Script Debugger"
	set myText to the selection of window 2
end tell

set AppleScript's text item delimiters to {return}

set aList to (paragraphs of myText)

set countList to {}

repeat with aString in aList
	set end of countList to {len:length of aString, val:(aString as text)}
end repeat
set countList to current application's NSArray's arrayWithArray:countList
set desc1 to current application's NSSortDescriptor's sortDescriptorWithKey:"len" ascending:true
set desc2 to current application's NSSortDescriptor's sortDescriptorWithKey:"val" ascending:true selector:"caseInsensitiveCompare:"
set sortedList to ((countList's sortedArrayUsingDescriptors:{desc1, desc2})'s valueForKey:"val") as list


set newText to sortedList as text
tell application "Script Debugger"
	set the selection of window 1 to newText
end tell

It seems to be something to do with the presence of the Script Debugger ‘tell’ statement above it. Without that, or if the ‘tell’ statement’s moved to a handler below the rest of the code, there’s no problem (on my machine).

By the way, isn’t the ‘use AppleScript’ line supposed to mention a version number?

Right. Because Ed’s presumably running it in Script Debugger, sending an event to itself effectively defines current application as Script Debugger, wich knows nothing of the variable NSArray. It should run fine from another app, like Script Editor, or even from Script Debugger’s Scripts menu.

There’s also no need to build a list of records. The guts of the script could be like this:

set countList to current application's NSArray's arrayWithArray:(paragraphs of myText)
set desc1 to current application's NSSortDescriptor's sortDescriptorWithKey:"length" ascending:true
set desc2 to current application's NSSortDescriptor's sortDescriptorWithKey:"self" ascending:true selector:"caseInsensitiveCompare:"
set sortedList to (countList's sortedArrayUsingDescriptors:{desc1, desc2}) as list

I’ve faced a couple of times this issue.
My workaround is to call the app by its ID (the 4 char ID does not take care of the version number…)

use framework "Foundation"
use framework "AppKit"
use scripting additions

tell application id "asDB" to set myText to (selection of script window 2)
set countList to current application's NSArray's arrayWithArray:(paragraphs of myText)
set desc1 to current application's NSSortDescriptor's sortDescriptorWithKey:"length" ascending:true
set desc2 to current application's NSSortDescriptor's sortDescriptorWithKey:"self" ascending:true selector:"caseInsensitiveCompare:"
set sortedList to (countList's sortedArrayUsingDescriptors:{desc1, desc2})
set finalString to sortedList's componentsJoinedByString:return -- or linefeed
tell application id "asDB" to set (selection of script window 2) to (finalString as string)
1 Like

@ionah: That’s an excellent workaround. I wouldn’t be surprised if the four-character IDs are no longer supported at some stage, but then it would just be a matter of using “proper” IDs.

You’re thinking about Big Sur, I guess?

No, just in general. The CFBundleSignature isn’t even listed as deprecated any more, and you tend to find it only in apps that have been around for a long time. Without a registry to guarantee uniqueness, I’d imagine it has few friends. I can see someone one day deciding it’s one value fewer to be checking.

Jonas’ solution works just fine (with a couple tweaks to make it sort descending).

Thanks!