chibop chibop - 11 months ago 45
AppleScript Question

AppleScript JXA Filtering Table With Many Rows with Same Name But Different Items

I have a huge table with many rows that have same name but different items in each row. If I execute the following

rows = table.rows.whose(searchFilter)()

And then if I check rows.length, I get the right number for the search. However, the arrays has only first row repeated multiple times. I guess it's because all the rows have the same name, and whose returns object specifiers based on byName(). I can filter by going through each row with JavaScript, but it takes really really long time. Whose seems filtering the right one much much more quickly, but returns wrong rows. Is there a workaround for this?


foo foo
Answer Source

You don't say what app you're scripting (which would help), but it sounds like it's not a JXA issue (for once) but an application one, as it's the target application that decides whether to return by-index, by-name, or by-id specifiers. Only by-id specifiers are guaranteed to be both stable and unique (their only disadvantage is that unlike the other forms the ID values aren't human-readable), but a lot of apps return by-index or by-name forms; the former being a problem if elements move around, the latter if element names aren't unique.

I think your only practical option is to get the row values to match, then enumerate that yourself to construct your own by-index specifier when a set of row values matches your requirements. This way you're still only sending a few Apple events in total (i.e. one AE to retrieve all of the values from a single column), instead of sending several events per row. Handling an AE is an expensive operation, so if you can use fewer, more complex queries to retrieve the same data, that will work out much cheaper than using lots and lots of simple ones, even if you still to collate the data yourself to get it into the form you actually want.

e.g. In AppleScript [1], you might write something like:

tell app "Whatever"
    set allFoos to get value of cell "foo" of every row of theTable
    set allBars to get value of cell "bar" of every row of theTable
    set foundRefs to {}
    repeat with i from 1 to length of allNames
        if item i of allFoos is myFoo and item i of allBars is myBar then
            set end of foundRefs to row i of theTable
        end if
    end repeat
end tell
-- foundRefs list now contains by-index refs to the matched rows

(Here's another example if it helps illustrate the point.)

Figuring out how to write the equivalent code in JXA is left to anyone foolish enough to use that broken-ass POS in the first place. [2]


[1] Ironically AppleScript lists have O(n) lookup performance due to crappy internal implementation (like JS's Array type, AS lists are actually vector arrays so should be O(1), but getting them to actually behave that way requires kludging in extra AS code to trick the runtime into bypassing the crappy bit). So the AppleScript code shown will perform abnormally badly but its purpose here is only to demonstrate the general algorithm, not to be a production script, so I'm not going to obfuscate it with kludgy crap [2].

[2] There's a reason I call down poxes upon both AS's and JXA's houses, and stick to using appscript myself. Blame Apple for pissing one of their greatest, most user-empowering innovations (end-user desktop automation) straight down the drain and not even realize they've done it.