While KM doesn't fully support array variables, any variable with delimeters is sort of an array: You can reference an item in a position. So given the variable myTest with contents a,b,c, then...
%Variable%myTest[1]% = a, ...[2] = b, and ...[3] = c
The problem is you can only refer to these specific positions to read their values; you cannot write to a specific position—you can only write the full variable. So while these semi-arrays are great for storing lots of information in one spot, they're not so good if you want to update that information.
But there's actually a relatively simple way to do it, at least for small relatively static arrays. Given the same example from above, if I want to change a,b,c to a,foobar,c I can do so like this:
Set Variable myTest to text: %Variable%myTest[1]%,foobar,%Variable%myTest[3]%
This seems obvious in hindsight, but I searched the forums and didn't find anything similar, and it took me a few minutes to reason through ... so I thought it might be useful for others. I wouldn't want to use this method for a 20-element array that's full of often-changing dynamic data, but for small occasional-use arrays, it works great.
This is a nice insight. I can see this being useful for say, the coordinates of a window where Keyboard Maestro saves the four bits of data in a fixed order left, top, width, and height in a comma-delimited numerical string. Your idea would allow one coordinate of the four to be changed at a later stage, whilst leaving the others alone. I'm sure there are many other uses too.
Two years on, I figure I should update this topic with the method I've been using, which is regular expression replacements, like this:
The above would replace the second item in the array, regardless of how long the array is—the expression captures the first field as $1, then doesn't capture the field to be replaced, and captures everything after that as $2. The replacement puts the first part back ($1), then the value I want to set, then the rest ($2), whether that's one, two, or ten more fields. Because I include the commas in the captures, I don't even have to type those.
This method has a huge advantage over the other in terms of flexibility: If I add an item to my array variable (as a new last item in the array), with this method I only have to modify any commands that set the previous end-of-element array value: They'd need to be modified to not capture everything into the last group. But all other calls could remain untouched, as they simply say "and the rest of the values" in their capturing regex.
It's also a heck of a lot faster to complete, in terms of not having to copy/paste multiple array formula references into the Set Variable field. Less readable, of course, but I'm fine with that.
Macros are always disabled when imported into the Keyboard Maestro Editor.
The user must ensure the macro is enabled.
The user must also ensure the macro's parent macro-group is enabled.
System Information
macOS 13.6.1
Keyboard Maestro v11.0.1d1
Example output:
Some points to note:
Setting array element 0 (zero) causes the action to fail since element zero holds the array size.
Setting an element beyond the size of the array extends the array to accommodate the new element. For example setting array element 15 of a 3-element array extends the size of the array to 15.
Setting the element -1 of an array actually sets the last element. Setting the -2 element sets the next-to-last element. And so on...
For an array of size N, setting any element -N-1, or -N-2, or -N-3 etc results in no change to the array and no error. I would have thought this should raise an error - @peternlewis ?
Excellent news, that's a very nice addition! But for backwards compatibility, I probably shouldn't start relying on it until I'm ready to make my macros KM11 only, right?
I did not know about this alternate \1 notation either, but as per the wiki both notations are accepted syntax in KM:
For regular expressions, the replacement can refer to capture groups using either $1 or \1 notation (eg %Calculate%CHARACTERS(\1)% would be the count of characters in the first capture match (v8+)), or named capture groups (using (?<name>...) with the notation ${name}.
Then I noticed the \n after the array index in @ComplexPoint's example. But \n didn't work for me. I had explicitly created the list with %Return% characters and it took \r to match them.
When I got the \r delimiter specified in both places, it works.
I also noticed that, when I had the syntax right, I could use the "variable preview" line at the bottom to "inspect" the variable and verify that I was using the right index. In between my first attempt and my successful one, the list had increased by one item so the item I wanted to edit was now [11]\r instead of [10]\r.
Also, a trick I've become fond of: I added this action at the end of another macro that I'm working on and executed it with the Try button at the bottom of the Editor window. Now that I've tested it, I'll delete that action.