Thanks, Shane. Seems I got lost in the documentation. Back on track incorporating everything I’ve learned so far.
My process: Create NSDictionary for efficient de-duplication of keys to remove redundant values, use NSDictionary values to build a ‘delta NSSet’, use ‘delta NSSet’ in predicate with further partial-string matches across full NSArray of library items. The final result is a unique deletion list. Sharing the code in-case anyone finds it useful on their ASOC journey…
use framework "Foundation"
tell application "Music"
set theID to current application's NSArray's arrayWithArray:(get persistent ID of every file track of library playlist 1)
set theLocation to current application's NSArray's arrayWithArray:(get location of every file track of library playlist 1)
end tell
set myLocationDict to current application's NSDictionary's dictionaryWithObjects:theID forKeys:theLocation
set myUniqueLocationID to current application's NSSet's setWithArray:(myLocationDict's allObjects())
set myDuplicateLocationID to current application's NSMutableSet's setWithArray:theID
myDuplicateLocationID's minusSet:myUniqueLocationID
set thePosixPath to (theLocation's valueForKey:"path")
set myPosixArray to my makeArrayQuickly(theID, thePosixPath)
set thePred to current application's NSPredicate's predicateWithFormat_("thePosixPath = nil OR NOT thePosixPath CONTAINS '/Music/' OR thePosixPath CONTAINS '/.Trash/' OR theID IN %@", myDuplicateLocationID)
set myDeletionArray to (myPosixArray's filteredArrayUsingPredicate:thePred)
on makeArrayQuickly(theID, thePosixPath)
set theID to theID as list
set thePosixPath to thePosixPath as list
script o
property oID : theID's items
property oPosixPath : thePosixPath's items
property oResult : {}
end script
repeat with i from 1 to (count o's oID)
set end of o's oResult to {theID:item i of o's oID, thePosixPath:item i of o's oPosixPath}
end repeat
set theResult to current application's NSMutableArray's arrayWithArray:(o's oResult)
return theResult
end makeArrayQuickly
Although I’m content with the time to complete for 15K items, I still keep coming back to makeArrayQuickly(). Using script object properties is amazingly fast, although it seems like a ‘workaround’ and I hope I’m not missing something simple when it comes to array creation. We can create a NSDictionary in a split second but not an NSArray without a repeat loop for the results similar in the format in the example below. Or is there another way?
(NSArray) {
{
theID:“3F80FAB1127481EF”,
thePosixPath:“/Users/USER/.Trash/01 - Downtown Shutdown (Eva Shaw Remix).mp3”
},
{
theID:“42D67D14E4598F82”,
thePosixPath:“/Users/USER/Music/TEST/04 - Downtown Shutdown (The Revenge Dubstramental).mp3”
},
{
theID:“04A543FB688D9C23”,
thePosixPath:“/Users/USER/Music/TEST/03 - Downtown Shutdown (The Revenge Remix).mp3”
},
{
theID:“9D18E2D0D48445C8”,
thePosixPath:“/Users/USER/Music/TEST/1-01 - Sho-Nuff - Tonite.mp3”
},
{
theID:“237E8FB89A0FBC17”,
thePosixPath:“/Users/USER/Music/TEST/1-01 - Sho-Nuff - Tonite.mp3”
}
}
Below are 4 ways I have tested. I’m interested in learning the fastest way for NS values only. At the moment, this example reading NS values only (#1 NSArray) is actually the slowest out of all.
use framework "Foundation"
tell application "Music"
--Setup NS Arrays for testing comparison
set theNSID to current application's NSArray's arrayWithArray:(get persistent ID of every file track of library playlist 1)
set theNSLocation to current application's NSArray's arrayWithArray:(get location of every file track of library playlist 1)
set theNSPosixPath to (theNSLocation's valueForKey:"path")
--Setup Applescript lists for testing comparison
set theASID to theNSID as list
set theASPosixPath to theNSPosixPath as list
--Test 2 methods of creating the same NSMutableDictionary
log "creating NSDictionary from NS values" ---0.02 SECONDS
set theNSDict to current application's NSMutableDictionary's dictionaryWithObjects:theNSPosixPath forKeys:theNSID
log "finished dictionary from NS values"
log "creating NSDictionary from Applescript List values" ---0.38 SECONDS
set theASDict to current application's NSMutableDictionary's dictionaryWithObjects:theASPosixPath forKeys:theASID
log "finished dictionary from Applescript List values"
--Test 4 methods of creating the same NSMutableArray
--#1 NSArray : 21 SECONDS
log "#1 NSArray : create NSMutableArray from NS values"
set myArrayWithNSvalues to current application's NSMutableArray's alloc's init()
repeat with i from 1 to theNSID's |count|()
(myArrayWithNSvalues's addObject:{theNSID:theNSID's objectAtIndex:(i - 1), theNSPosixPath:theNSPosixPath's objectAtIndex:(i - 1)})
end repeat
log "finished NSMutableArray from NS values"
--#2 NSArray : 17 SECONDS
log "#2 NSArray : create vanilla list from applescript list values - then convert to NSMutableArray"
set MyListWithASListValues to {}
repeat with i from 1 to count of theASID
set end of MyListWithASListValues to {theID:item i of theASID, thePosixPath:item i of theASPosixPath}
end repeat
set myConvertedFromListArrayWithApplescriptLists to current application's NSMutableArray's arrayWithArray:MyListWithASListValues
log "finished NSMutableArray from applescript list values - then convert to NSMutableArray"
--#3 NSArray : 11 SECONDS
log "#3 NSArray : create NSMutableArray from applescript list values" ---
set myArrayWithApplescriptLists to current application's NSMutableArray's alloc's init()
repeat with i from 1 to count of theASID
(myArrayWithApplescriptLists's addObject:{theID:item i of theASID, thePosixPath:item i of theASPosixPath})
end repeat
log "finished NSMutableArray from applescript list values"
--#4 NSArray : 0.01 SECONDS
log "#4 NSArray : create NSMutableArray from script object properties" ---0.01 SECONDS
script o
property oID : theASID's items
property oPosixPath : theASPosixPath's items
property oResult : {}
repeat with i from 1 to count of o's oID
set end of o's oResult to {item i of o's oID, item i of o's oPosixPath}
end repeat
end script
set myArrayWithScriptObjectProperties to current application's NSMutableArray's arrayWithArray:(o's oResult)
log "finished NSMutableArray from script object properties"
end tell
Let me know if anyone has any further suggestions to try?
Thanks