One of the useful classes in Cocoa (and other languages) is the set, which is like a list except each item can only appear once. Sets are not normally ordered like lists, but Cocoa also has ordered lists, which maintain their order. Anyway, they are a good class to show the convenience of using ASObjC-based script libraries in Mavericks.
Save this script as a .scptd file in ~/Library/Script Libraries/ or /Library/Script Libraries/, following the instructions here: macscripter.net/viewtopic.php?id=41638
use framework "Foundation"
script BaseObject -- the parent script object, required for AppleScriptObjC inheritance
end script
on smartSetWith:aList -- call this to make a new smartList
script SmartSet
property parent : BaseObject -- for inheritance
property theSetStore : missing value -- where the array is stored
on countOfSet() -- get count of items
return theSetStore's |count|() as integer
end countOfSet
-- get objects and indexes
on objectAtIndex:anInteger
set anInteger to my correctIndex:anInteger
set theResult to theSetStore's objectAtIndex:anInteger
return my coerceToASClass:theResult
end objectAtIndex:
on objectsFrom:anInteger toIndex:endInteger -- get range of objects
set anInteger to my correctIndex:anInteger
set endInteger to my correctIndex:endInteger
set theIndexSet to current application's NSMutableIndexSet's alloc()'s init()
theIndexSet's addIndexesInRange:(current application's NSMakeRange(anInteger, endInteger - anInteger + 1))
return (theSetStore's objectsAtIndexes:theIndexSet) as list
end objectsFrom:toIndex:
on indexOfObject:anObject
try -- will error if not found because NSNotFound is too big to coerce to an integer
set theResult to ((theSetStore's indexOfObject:anObject) as integer) + 1
on error
return 0
end try
return theResult
end indexOfObject:
-- add objects
on addObject:anObject -- adds to end
theSetStore's addObject:anObject
end addObject:
on addObjectsFromArray:anObject -- adds to end
theSetStore's addObjectsFromArray:anObject
end addObjectsFromArray:
on insertObject:anObject atIndex:anInteger -- insert object
set anInteger to my correctIndex:anInteger
theSetStore's insertObject:anObject atIndex:anInteger
end insertObject:atIndex:
-- remove objects
on removeObject:anObject
theSetStore's removeObject:anObject
end removeObject:
on removeObjects:newList
theSetStore's removeObjectsInArray:newList
end removeObjects:
on removeObjectAtIndex:anInteger
set anInteger to my correctIndex:anInteger
theSetStore's removeObjectAtIndex:anInteger
end removeObjectAtIndex:
on removeObjectsFrom:anInteger toIndex:endInteger
set anInteger to my correctIndex:anInteger
set endInteger to my correctIndex:endInteger
theSetStore's removeObjectsInRange:(current application's NSMakeRange(anInteger, endInteger - anInteger + 1))
end removeObjectsFrom:toIndex:
-- replace objects
on replaceObjectAtIndex:anInteger withObject:anObject
set anInteger to my correctIndex:anInteger
theSetStore's replaceObjectAtIndex:anInteger withObject:anObject
end replaceObjectAtIndex:withObject:
on setObject:anObject atIndex:anInteger -- replace or add, depending on index
set anInteger to my correctIndex:anInteger
theSetStore's setObject:anObject atIndex:anInteger
end setObject:atIndex:
-- swap objects
on swapObjectAtIndex:anInteger withObjectAtIndex:endInteger
set anInteger to my correctIndex:anInteger
set endInteger to my correctIndex:endInteger
theSetStore's exchangeObjectAtIndex:anInteger withObjectAtIndex:endInteger
end swapObjectAtIndex:withObjectAtIndex:
-- sort objects
on sortIgnoringCase()
my sortUsingSelector:"localizedCaseInsensitiveCompare:"
end sortIgnoringCase
on sortConsideringCase()
my sortUsingSelector:"localizedCompare:"
end sortConsideringCase
on sortLikeFinder()
my sortUsingSelector:"localizedStandardCompare:"
end sortLikeFinder
on standardSort() -- use for other than strings
my sortUsingSelector:"compare:"
end standardSort
-- query the set
on containsObject:anObject -- whether set contains an object
return ((theSetStore's containsObject:anObject) as integer = 1)
end containsObject:
on containsObjects:listOrArray -- whether set contains all objects in the list
set newSet to current application's NSSet's setWithArray:listOrArray
return ((newSet's isSubsetOfSet:(theSetStore's |set|())) as integer = 1)
end containsObjects:
on intersects:listOrArray -- whether list items and set intersect
set theSet to current application's NSSet's setWithArray:listOrArray
return ((theSetStore's intersectsSet:theSet) as integer = 1)
end intersects:
on intersectsInOrder:listOrArray -- whether list in order and set intersect
set theSet to current application's NSOrderedSet's orderedSetWithArray:listOrArray
return ((theSetStore's intersectsOrderedSet:theSet) as integer = 1)
end intersectsInOrder:
on isSubsetOf:listOrArray -- whether set is a subset of the list
set theSet to current application's NSSet's setWithArray:listOrArray
return ((theSetStore's isSubsetOfSet:theSet) as integer = 1)
end isSubsetOf:
on isSubsetInOrderOf:listOrArray -- whether set is a subset of the list in matching order
set theSet to current application's NSOrderedSet's orderedSetWithArray:listOrArray
return ((theSetStore's isSubsetOfOrderedSet:theSet) as integer = 1)
end isSubsetInOrderOf:
on minusSet:listOrArray -- subtract objects in list from set
set theSet to current application's NSSet's setWithArray:listOrArray
theSetStore's minusSet:theSet
end minusSet:
on unionSet:listOrArray -- add objects in list to set if they are not in it already
set theSet to current application's NSOrderedSet's orderedSetWithArray:listOrArray
theSetStore's unionOrderedSet:theSet
end unionSet:
on intersectSet:listOrArray -- remove objects not in list from set
set theSet to current application's NSSet's setWithArray:listOrArray
theSetStore's intersectSet:theSet
end intersectSet:
-- return as list/array
on asArray() -- return as array for further use
return theSetStore's array()
end asArray
on asList() -- return as list
return theSetStore's array() as list
end asList
-- handlers for script's use
on correctIndex:anInteger -- for script's use; convert AS index to Cocoa index
if anInteger < 0 then
return anInteger + (my countOfSet())
else
return anInteger - 1
end if
end correctIndex:
on coerceToASClass:anObject -- for script's use; coerce to AS class for return
if ((anObject's isKindOfClass:(current application's NSArray)) as integer = 1) then
return anObject as list
else -- coerce to list and return item 1; workaround to coerce item of unknown class
set anObject to anObject as list
return item 1 of anObject
end if
end coerceToASClass:
on sortUsingSelector:theSel -- for script's use
set theDesc to current application's NSSortDescriptor's sortDescriptorWithKey:"self" ascending:true selector:theSel
theSetStore's sortUsingDescriptors:{theDesc}
end sortUsingSelector:
end script
set theSetStore of SmartSet to current application's NSMutableOrderedSet's orderedSetWithArray:aList -- set initial value
return SmartSet
end smartSetWith:
The idea is that you create a SmartSet, manipulate it, then return it as a list using asList(). So for example:
use theLib : script "SmartSet lib" -- or whatever you called it
set mySet to theLib's smartSetWith:{4, 6, 1, 2, 3, 7, 1, 4, 3, 3, 7}
set uniqueList to mySet's asList()
This returns the list with duplicates removed. Or:
set mySet to theLib's smartSetWith:{4, 6, 1, 2, 3, 7, 1, 4, 3, 3, 7}
mySet's standardSort()
set sortedList to mySet's asList()
If you run the following and look at the log, you’ll probably get more idea:
set mySet to theLib's smartSetWith:{4, 6, 1, 2, 3, 7, 1, 4, 3, 3, 7}
log mySet's asList()
log (mySet's containsObject:8)
log (mySet's containsObject:1)
mySet's standardSort()
log mySet's asList()
mySet's insertObject:"hello" atIndex:2
log mySet's asList()
mySet's swapObjectAtIndex:2 withObjectAtIndex:-2
log mySet's asList()
mySet's replaceObjectAtIndex:-1 withObject:"blah"
log mySet's asList()
log (mySet's objectsFrom:3 toIndex:5)
mySet's removeObjectsFrom:3 toIndex:5
log mySet's asList()
mySet's unionSet:{6, 4, 8, 1, 4}
log mySet's asList()
mySet's minusSet:{6, 4, 9, 11}
log mySet's asList()
log (mySet's isSubsetOf:{6, "blah", 9, 1, 8})
log (mySet's containsObjects:{1, 8})