I have a database which only contains records whose name is a number. I’m trying to find out which numbers are missing. Is this possible with AppleScript? Starting with a modified version of this script (Access with AppleScript the history of a DEVONthink database) I’ll get the names of all records in the current database.
But how to find out which numbers are missing?
tell application "DEVONthink Pro"
set allRecords to contents of current database
set myData to {}
repeat with i from 1 to count of allRecords
set end of myData to name of item i of allRecords
end repeat
return myData
end tell
Make a repeat loop to extract to a string variable the name of each record whose type is not group. Put a & Return at the end of each line. After the repeat, put that string onto the clipboard. Paste it into Excel or Numbers. Sort, parse, and do your evaluation of missing numbers there.
Building a one-time tool in AppleScript to do all the testing and manipulation is not worth the effort, IMO.
-- Find missing numbers
-- This script is a demo, it only works with names like "78.html". To use it it's necessary to additionally extract the desired part of each record name
tell application id "DNtp"
try
set theRecords to selected records
if theRecords = {} then error "Please select some records"
set theNames to name without extension of selected records -- e.g. {"78", "163", "150"}
set theNames_sorted to my sort_list(theNames)
set theMissingNumbers to {}
if (item 1 of theNames_sorted) as integer ≠ 1 then set theNames_sorted to {0} & theNames_sorted
repeat with i from 1 to ((count theNames_sorted) - 1)
try
set startNumber to (item i of theNames_sorted) as integer
set endNumber to (item (i + 1) of theNames_sorted) as integer
repeat with j from startNumber + 1 to endNumber - 1
set end of theMissingNumbers to j
end repeat
end try
end repeat
return theMissingNumbers
on error error_message number error_number
if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
return
end try
end tell
on sort_list(theList)
considering numeric strings
set theIndexList to {}
set theSortedList to {}
repeat (length of theList) times
set theLowItem to ""
repeat with a from 1 to (length of theList)
if a is not in theIndexList then
set theCurrentItem to item a of theList as text
if theLowItem is "" then
set theLowItem to theCurrentItem
set theLowItemIndex to a
else if theCurrentItem comes before theLowItem then
set theLowItem to theCurrentItem
set theLowItemIndex to a
end if
end if
end repeat
set end of theSortedList to theLowItem
set end of theIndexList to theLowItemIndex
end repeat
end considering
return theSortedList
end sort_list
I supposed it works now, showing the progress in @pete31’s AppleScript faculties during the last four years;-) And also that it’s possible to solve any problem in any language, even those that do not have a sort function or a list comparison method…
For the sorting method, I’d suggest MacScripter / QuickSort Algorithm
Should be a bit “quicker” than the merge sort (? it is merge, isn’t it) here.
Personally, I do not even understand the problem. My only files named with numbers are those coming from a camera, and I do not import those in DT. And I couldn’t care less about any “holes” in the list of names.
Because I feel really mean today, the JavaScript version (bar error checking, admittedly)
(()=> {
let app=Application("DEVONthink 3");
let nameArray = app.selectedRecords.nameWithoutExtension();
let namesSorted = nameArray.sort(); // to get "biggest" name
let fullArray = [];
for (i = 1; i <= namesSorted[namesSorted.length -1]; i++) { // Array with all "names" from "1" to the last existing one
fullArray.push(""+i); // make sure that elements are strings
}
let difference = fullArray.filter(d => !nameArray.includes(d))
return difference;
})()
12 LOC vs. 52 (add some more for error handling). Maybe JavaScript does sometimes have some advantages over AppleScript – like C over Basic
Sorry didn’t meant to reply to your post. Thanks for the suggestion btw. Didn’t try it though, I really don’t like spreadsheet apps.
Actually I forgot to check whether the first item = “1”. Fixed.
Yep, stumbled upon this thread and got curious whether I could do it now.
Looking at the example {“78.html”, “150.html”, “163.html”} it was probably a problem with exporting from Zettelkasten.app. Never exported data from any app before and probably made all mistakes one can make.
Your script gets only the missing numbers from “1” to the first item. Funny as that’s exactly the part that I forgot in my prior version. I’m afraid you have to add some more lines
This assesment was not correct. However, due to the alphabetical sorting, it missed out on other cases.
So let’s amend that with a proper sort for numerical values:
let namesSorted = nameArray.sort(function(a,b) {
return (parseInt(a) - parseInt(b))
});
Now I have files "1", "2", "8", "12", and difference is
["3", "4", "5", "6", "7", "9", "10", "11"]
That should be ok, I think. Before the change, it stopped after 7. The script could probably be simplified by using fullArray to calculate the difference: Instead of adding all numbers from 1 to the last one, add only those that are not in namesSorted. 13 LOC, one loop less. Of course a lot less fun if one likes to type much