Separate Sets of Variables? [Solved]

Take a look at Variable Arrays in the Wiki:
Wiki Variable Arrays

Here's an example macro that starts or adds items to an array variable Var__Size. It keeps an index pointing to the latest values added. Resetting the index to 0 will start the list over.

Shoot, I messed up the initial IF statement. It should be IF ANY of the following are true, not if ALL of the following are true.

1 Like

Great. Thank you so much @kvanh . I will try this out. :grinning:

So... this looks like the critical bit of Syntax I was missing to include a Variable within a Variable name?

image

Sorry - I am still missing something...

I can see how to retreave Data from %Variable%Var__Size[VarIndex]%

But how do I write Data to %Variable%Var__Size[VarIndex]% ?

Is the logic that this stores the Data:

And this retreives it?

At the moment I just can't understand the logic that is going on with this.

It might help to give two actual Actions in my existing Macros.

Here is one Action that saves data:

And here is the Acton in the second Macro that makes use of this Data

What I would like to be able to write (but obviously I am using the wrong syntax) is something like this:

and this:

Sorry for not being able to follow this. And thank you for your help.

Unfortunately arrays in KM are not arrays at all - they’re just text strings, a bit like comma separated values, where the delimiter isn’t restricted to being a comma.

Furthermore, KM arrays are one-way meaning you can get individual elements out of them but you can’t write individual elements back to them. So when you try to update any array element you are doomed to failure.

In the past I had to do something like what you’re describing and after much searching I resorted to using KM dictionaries. Don’t get me wrong: it was not easy and getting my head around indirect references to dictionary names and keys almost drove me crazy.

I know this isn’t massively helpful to you but I hope you find it reassuring to know it can be done.

Since my experience, I’ve seen javascript become more “popular” in KM and I suspect that you could find a better solution to your problem using JS as it has real arrays and plenty of ways to manipulate them.

1 Like

Thanks @tiffle

Yes, that's what I was suspecting and probably why I've been going in circles...

Fortunately it's not too difficult to make a copy of the the two Macros and bulk rename all the Variables with a different value at the front (WSA__Application1 renamed to WSB___Application1 and so on) using @JMichaelTX's excellent Variable renaming Macro found here:

1 Like

Yes, @JMichaelTX is some kind of magician :wink:

2 Likes

There is another option that might work ok for you. I think you could leverage it to at least minimize the number of variable renames you have to do.

Dictionaries allow you to group related values together. So you could have a Set1 containing Size, Position, Area and Weight values, and Set2 containing different values for the same name. Then anywhere you want to use those values you could set a regular variable to contents of the Dictionary. You can use a variable for the set number to decide which dictionary to use.

https://wiki.keyboardmaestro.com/manual/Dictionaries

So, an example of creating a dictionary where the user enters a Set number:

Then in any other macro where you wanted to use that set of values, set a variable to contain the set number, then assign the values to the variables:

Thank you @kvanh for putting all the time in to help me with this. I will try Dictionaries tomorrow as it looks like that is going to be the way forward.

I generally don't like KM Dictionaries, but I think this is a great use case for them. I was going to suggest using a KM Global Variable that contains tab-delimited data for each set, and retrieve using RegEx.

Just for comparison, here's my approach of using a RegEx Table Lookup:

You store ALL of the set data in one KM global variable, which is a lookup table:

image

Example Output

image

Below is just an example written in response to your request. You will need to use as an example and/or change to meet your workflow automation needs.

Please let us know if it meets your needs.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

MACRO:   How To Use Different Sets of Data [Example]

-~~~ VER: 1.0    2021-05-26 ~~~
Requires: KM 8.2.4+   macOS 10.11 (El Capitan)+
(Macro was written & tested using KM 9.0+ on macOS 10.14.5 (Mojave))

DOWNLOAD Macro File:

How To Use Different Sets of Data [Example].kmmacros
Note: This Macro was uploaded in a DISABLED state. You must enable before it can be triggered.


ReleaseNotes

Author.@JMichaelTX

PURPOSE:

  • Demo How to Use Sets of Data using RegEx Table Lookup

HOW TO USE

  1. First, make sure you have followed instructions in the Macro Setup below.
  2. See the below "How to Use" Comment Action
  3. This macro is just an example written in response to your request. You will need to use as an example and/or change to meet your workflow automation needs.

MACRO SETUP

  • Carefully review the Release Notes and the Macro Actions
    • Make sure you understand what the Macro will do.
    • You are responsible for running the Macro, not me. ??
      .
      Make These Changes to this Macro
  1. Assign a Trigger to this Macro .
  2. Move this macro to a Macro Group that is only Active when you need this Macro.
  3. ENABLE this Macro, and the Macro Group it is in.
    • For more info, see KM Wiki article on Macro Activation
      .
  • REVIEW/CHANGE THE FOLLOWING MACRO ACTIONS:
    (all shown in the magenta color)
    • CHANGE To Your Set Data
      • Format:

REQUIRES:

  1. KM 9.0+ (may work in KM 8.2+ in some cases)
  2. macOS 10.12.6 (Sierra)+

TAGS: @Example @RegEx @TableLookup

==USE AT YOUR OWN RISK==

  • While I have given this a modest amount of testing, and to the best of my knowledge will do no harm, I cannot guarantee it.
  • If you have any doubts or questions:
    • Ask first
    • Turn on the KM Macro Debugger from the KM Status Menu, and step through the macro, making sure you understand what it is doing with each Action.

This looks very good - and not too many steps.

So, I am assuming the approach could be to first gather all the individual bits of Data to Variables and then use those Variables to build the Monster DND_Object_Sets Variable? And then from there call the individual Sets as needed using a version of your Example Macro.

What I am tying to figure out is how to build DND_Object_Sets Variable on the fly for each of the Sets.

I can see how I could incorporate this at the start of a Macro 2 to choose between say 3 Sets of Data. For example, at the head of Macro 2 I choose Set02 and that Set of Data is used for the rest of the Macro.

But how would I tell Macro 1 to overwrite the Data for just Set02 when I run it without also overwriting Set01 and Set03?

And this sounds like it should work too. The Dictionary being a kind of version of DND_Object_Sets - a single file with all the Data in, broken down into Sets of Data?

But I just can't understand the logic of how these Dictionaries work.

Again, I think I am creating confusion for myself by not uploading examples of my actual Macro elements. I didn't do that because the Macros are quite long.

But I have now uploaded the Group of Macros to the Macro Library on the Forum as they are stable and working as they are.

They save Workspaces on the fly that I might need to restore at a later date. In their present form they work well (for me at least) and have have been very useful. But they only Save and Restore a Single Workspace. To have them store and restore Multiple Workspaces I have been copying the Group and bulk changing the Variable names (as I mentioned earlier). This allows me to have my Sets of Workspaces to Save and Restore to - but it does mean if I edit any one of the Macros I have to edit it in all the Groups.

The ideal would be to have just one Macro that does the Saving and tell it at the start which Set to Save to. And just one Restore Macro and tell it at the start which Set to Restore.

Dictionaries work very similarly to Arrays (this is in programming in general) except instead of having a number as the index into the values you have a name. This is called a key-value pair. The dictionary name groups the keys and values together.

So in a traditional array you have multiple values like so:
array_name = (value1,value2,value3)
and can access individual values with
new_var1 = array_name(1)
new_var2 = array_name(2)
new_var3 = array_name(3)
(note, arrays in most languages are zero indexed (first value is at index 0, not 1) so this example isn't exact for them)

In a dictionary instead you name each entry and assign it's value to that name.
dict_name[key1]=value1
dict_name[key2]=value2
dict_name[key3]=value3

then you use the same dictionary/key name to recover the value
new_var1 = dict_name[key1]

In KM accessing dictionaries as a token via:
%Dictionary[dict_name,key1]%

One of KM's super powers is the ability to expand tokens in a variable name then use the result as new variable name, the % can make it hard to read, but it is absolutely a fabulous feature.

varDictName = "Set1"
%Dictionary[%Variable%varDictName%,key1]%

Now your token can refer to multiple dictionaries just by changing the varDictName to be the name of the dictionary you want to use. Or if you just want to embed a number:

varDictNum = 2
%Dictionary[Set%Variable%varDictNum%,key1]%

You can do the same with key names and use variable substitution to change which key you're looking at (I rarely use this).

If in KM you ever need a "true" array, just make your key names into numbers:
secretArray[1] = array_value_1
secretArray[2] = array_value_2
secretArray[3] = array_value_3

This is closer to a true array but can have differences like the numbers don't have to be consecutive and deleting an item leaves a hole, the indexes aren't renumbered.

1 Like

So, I think I am beginning to get this. When I thought of a "Dictionary" I was thinking all the Variables in my Macro would end up stored in one big Dictionary.

But it looks like I can make a "Dictionary" for each Variable I want to store and "Key" number for what actual Data Sets I want them to store or reference?

So, for my Macros I might set up:

"Dictionary Left" to store the left coordinate of a Windowas a number.
"Dictionary Top" to store the top coordinate of a Windowas a number.
"Dictionary Width" to store the width of a Windowas a number.
"Dictionary Height" to store the height of a Window as a number.

And then use the "key" number to allow me to store different values to each Dictionary.

So "Dictionary Left" would have a choice via the "key" number.

Something like "Dictionary Left" "Key 1" (or "Key 2" etc)

I know the syntax is not right for Keyboard Maestro but is this the concept?

Yes, that would work. It's more like the traditional array you were looking at to begin with.

Another option is to group all the related coordinates together in a single dictionary and have multiple dictionaries for each window.

Let's suppose you want to save the coordinates for 2 window both the methods work.

Method 1 dictionary per coordinate, key name is window name:
dict_left[Win1] = window_1_left_coordinate
dict_left[Win2] = window_2_left coordinate

Now your dict_left can store the left coordinate for as many windows as you want. Just add a new Key name for the new window. Expand by creating a dictionary for each of the other coordinates and use the same key name:

dict_top[Win1]=Window_1_top_coordinate

Method 2: Dictionary per window, all coordinates in that dictionary:
dict_Win1[Left]=Window_1_left_coordinate
dict_Win1[Top]=Window_1_top_coordinate
dict_Win1[Width]=Window_1_width_value
dict_Win1[Height]=Window_1_height_value

Now to store a new window just create a new dictionary name:
dict_Win2[Left]=Window_2_left_coordinate

Which ever method makes the most sense to you should work.

1 Like

Yes. If you will give us an example of how you get your source data for each object maybe we could make some suggestions.

Add Set

You can use the Set Variable to Text action with the "Append" option (set in the Gear menu).

Assuming that you have set the "Local__..." variables from your source object:
image
NOTE: The variables are separated by TAB character. Everything is on one line. The KM Editor shows a soft word wrap that will NOT be in the data.

Update Set

You would use a KM Search and Replace action

Assuming that Local__SetID_ is "Set02"
image

I have several Macros that use this design and they work very well.

Questions?

Thank you @kvanh and @JMichaelTX
I can see two solutions here both equally promising. Is there any way to mark both as "the solution" in this thread?

Eureka! I have it now.

For my use this approach works (in this example to Save and Recall the name of the Front Application).

(VAR__ and DCT__ at the start of the Variable and Dictionary names are purely for my own annotation so that I can clearly see what is a Variable and what is a Dictionary.)

To Set a Value

To Recall a Value

The moment it became clear, was linking the method of creating a Dictionary Value to the method of Recalling a Value from it. And the fact that the Key could be a Variable is the solution to my problem.

So, the Dictionary becomes a fancy Variable that allows different values to be saved and recalled governed by a Key - which is what my question at the start of this thread was asking.

The Wiki page confused me because the example it uses for Storing is different to the example it uses for Recalling:

I'm trying to work out Shop Prices and Drink types and Costs that are saved in a Dictionary and then given First Names and Persons as the Recall Example :thinking:

Anyway thank you so much to @kvanh, @tiffle and @JMichaelTX I think I am there now.

3 Likes

Yes, that isn’t very helpful. It should end with the same example it started with. Maybe the wiki can be tidied up?

Anyway - good job getting your head around it :smiley:

1 Like

Congrats to finding a solution that works for you.
:+1:

1 Like

At present the Wiki says this:

I think I would have been a lot less confused if the Wiki had said something more like this:

3 Likes