How do I fast sort paths by length of path as item

G’day

I’m trying to find a fast way of sorting paths to folders by length of the path. I’m trying to re-name folders, but if they’re re-named in the wrong order, paths to other folders are disrupted.

I’ve found that if I sort the paths from longest to shortest, then everythings ok.

Why does the first script work, but the second doesn’t?

TIA

This script works, but is slow.


set keepPathNames to {}
			set keepNames to {}
			my RenameInFolders(TheItem2, thetype)
			
			copy keepPathNames to tempstring
			set tempPathNames to {}
			set tempPaths to {}
			set tempnames to {}
			set keepnumber to 0
			repeat
				set maxlength to 0
				repeat with x from 1 to number of items of tempstring
					set y to length of (item x of tempstring as string)
					if y > maxlength then
						set maxlength to y
						set keepnumber to x
					end if
				end repeat
				if keepnumber > 0 then copy text item keepnumber of tempstring to end of tempPathNames
				if number of items of tempstring < 2 then
					exit repeat
				else if keepnumber = (number of items of tempstring) then
					set tempstring to items 1 thru -2 of tempstring
				else if keepnumber = 1 then
					set tempstring to items 2 thru end of tempstring
				else
					set tempstring to ((items 1 thru (keepnumber - 1)) of tempstring) & ((items (keepnumber + 1) thru end) of tempstring)
				end if
			end repeat
				

This script is fast, but the lengths don’t seem to be sorted correctly.


copy keepPathNames to thelist
set xx to count of thelist
if xx > 1 then
	ignoring case, punctuation and white space
		repeat
			repeat with x from 1 to xx - 1
				set firstGo to length of (item x of thelist as string)
				set SecondGo to length of (item (x + 1) of thelist as string)
				if (firstGo < SecondGo) then
					set swapthis to item x of thelist as string
					set item x of thelist to item (x + 1) of thelist as string
					set item (x + 1) of thelist to swapthis
				end if
			end repeat
			set xx to xx - 1
			if xx = 1 then exit repeat
		end repeat
	end ignoring
end if

Model: G5 1.8 GHz
AppleScript: 2.1.1
Browser: Safari 419.3
Operating System: Mac OS X (10.4)

This approach will present a list in order of folder depth where F is the list of aliases to the folders within the chosen folder, and C is the list of their “depths”:


set AppleScript's text item delimiters to ""
tell application "Finder" to set F to (folders of entire contents of (choose folder) as alias list)
set C to {}
set tid to AppleScript's text item delimiters
set AppleScript's text item delimiters to ":" as Unicode text
repeat with aF in F
	set T to text items of (aF as string)
	set C's end to count T
end repeat
set AppleScript's text item delimiters to tid

Presumably, you mean that’s because the other folders may be inside the renamed ones.

If you sort the paths lexically, each folder will be sorted immediately before any folders it contains. You can then either work backwards through the list or reverse the list. Alternatively, if you use aliases instead of paths, the order in which you rename the folders won’t matter.

Thanks Adam. That’s certainly faster.

Unfortunately the actual script I’m using has to keep track of two lists, and arrange the second along with with the firsts sort.

I’ve realized my problem was with using the ‘set’ command rather than using ‘copy’

My script now works, and looks like this, bit slow :confused: but…


		set xx to count of keepPathNames
			if xx > 1 then
				ignoring case, punctuation and white space
					repeat
						repeat with x from 1 to xx - 1
							set firstGo to length of (item x of keepPathNames as string)
							set SecondGo to length of (item (x + 1) of keepPathNames as string)
							if (firstGo < SecondGo) then
								copy item x of keepPathNames to swapthis
								copy item (x + 1) of keepPathNames to item x of keepPathNames
								copy swapthis to item (x + 1) of keepPathNames
								copy item x of keepNames to swapthis
								copy item (x + 1) of keepNames to item x of keepNames
								copy swapthis to item (x + 1) of keepNames
							end if
						end repeat
						set xx to xx - 1
						if xx = 1 then exit repeat
					end repeat
				end ignoring
			end if

Model: G5 1.8 GHz
AppleScript: 2.1.1
Browser: Safari 419.3
Operating System: Mac OS X (10.4)

If you have two lists and want to sort on one and keep the other in sync, this handler by Kai originally, will do it. It’s easily extensible to more lists by adding the new term to the handler argument and then adding that term below the SecondList’s statements.


to sort2Lists(sortList, SecondList) -- sorts on the first, keeps the second in sync.
	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
		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
			else
				set sortList's item (i - 1) to s
				set SecondList's item (i - 1) to r
				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
		end if
	end repeat
	return {sortList, SecondList}
end sort2Lists

If the lists are really large (several hundred items, then it is useful to speed up the sort by using an internal script as follows:


to sort2Lists(sortList, SecondList) -- sorts on the first, keeps the second in sync.
	-- This version is much faster than the other if the lists are large.
	script O
		property L1 : missing value
		property L2 : missing value
	end script
	set O's L1 to sortList
	set O's L2 to SecondList
	tell (count O's L1) to repeat with i from (it - 1) to 1 by -1
		set s to (O's L1)'s item i
		set r to (O's L2)'s item i
		repeat with i from (i + 1) to it
			tell (O's L1)'s item i to if s > it then
				set (O's L1)'s item (i - 1) to it
				set (O's L2)'s item (i - 1) to (O's L2)'s item i
			else
				set (O's L1)'s item (i - 1) to s
				set (O's L2)'s item (i - 1) to r
				exit repeat
			end if
		end repeat
		if it is i and s > (O's L1)'s end then
			set (O's L1)'s item it to s
			set (O's L2)'s item it to r
		end if
	end repeat
	return {O's L1, O's L2}
end sort2Lists

G’day

Thanks Adam, the latter script works a treat.

I added a third list, with the first sort-on list being a list of pathname lengths, the second being the paths, the third being the path names (or re-names) and reversed the order of sorting, and all is well.

preparing and adding the first list saved constantly referring to tell (O’s L1)'s item i to if length of s < length of it then

Regards

Santa

Model: G5 1.8 GHz
AppleScript: 2.1.1
Browser: Safari 419.3
Operating System: Mac OS X (10.4)