Store Values in Dynamically Created Variables?

Hi,

Can someone suggest a good way to store values as follows:

So, I have a macro that will run and gather let’s say 6 different values with titles: Name, Type, Length, Cost, Project. This will happen multiple times over 2 weeks and possibly total up to 50 unique values for each of those. So that I could have say 50 items that each have a Name, Type, Length, Cost, Project etc.

I was thinking about doing something like

Item1Name
Item1Type
Item1Length
Item1Cost
Item1Project

Item2Name etc.

And ideally each time the main macro ran it would store these values in the ‘next’ available “Item”, so if something is already stored in “Item4Name… etc.” then it would use “Item5Name” etc. I could create all these “Item” variables up to 50, but then I’d need to specifically reference “Item5Name…Item6Name … etc.” with lots of If / Then loops. Is there a way to have the Variables created dynamically and have them looked at automatically to determine if they’re full and if so have the macro create the next one etc.

After a few weeks I would set all these “Item” variables back to ‘empty’ and start again.

Does that make sense?

Any help is appreciated!

Thanks

The design greatly depends on what you want to do with the data after you have collected it. Let’s say you have all the data in a KM variable (or variables), then what?

An idea that pops into my head is to use JavaScript (JXA actually) and store the data in a JSON string format. This would allow you to easily import/export the data between KM and a JXA script, and add to, or remove, data at any time. The data would be an array of objects. This makes it very easy to use, search, sort, etc the data within JavaScript.

So, if you can detail your workflow, the more detail the better, perhaps we can offer a more concrete solution. Please use real-world data, and be specific about any apps and/or web sites you use.

My advice would be to wait a week or two.

6 Likes

Christmas in September? :wink:

Thanks for the idea.

This is related to my post from yesterday regarding generating invoices from a spreadsheet.

Basically, I was trying to figure out the best way to transfer the “Task List” values into these different spreadsheets and I came across a post from you that discussed something sort of similar (only to a Web Form instead) - and you suggested that a first step would be getting the data into KM variables. Well, that made me realize that the data in this “Task List” is actually ‘coming’ from KM to begin with (from variables) - so it would make more sense to take the data directly from KM and put it in the Invoice spreadsheet. The issue there is that while this data is ‘coming’ from KM, it gets overwritten multiple times a day - so I’d need to ‘store’ the variables in KM - OR - this is exactly what the “Task List” does, stores the data and then I create the invoices from that. So both solutions will have their advantages.

Peter, not really asking for you to ‘give anything away’, but are we possibly talking about a way to generate a KM variable with a name that contains a number - that is sort of also the ‘counter’? So something like:

“Set variable to Item%[Variable+1]%Name”. Please feel free to once again advise me to wait a week or two :wink: … otherwise I can try to accomplish something similar maybe in AppleScript or JS.

Thanks guys!

You can do that already. The Variable field of the Set Variable action can contain tokens, and the Value of Named Variable filter can go in the other direction, so you can use a Counter index and use that in variable names to read and write them now.

Something like this:

But when v8 is released, there will be a better way.

1 Like

Nice!

But in reality the data must come from some other source than KM.

So, again,

Please start with the original source of your data.
Perhaps KM 8 will make this easier, but we still need to know the workflow.

Right, well, the data is coming from multiple different places. We’re talking a bunch of different KM macros grabbing different parts of the “Task List” data. For instance, KM is running macros that grab a folder path that is then stripped of everything but the ‘Project Name’, and it grabs the path of the Task audio file that then runs a script to pull the duration of the file, the Task Name is taken from the main app that is producing the audio file in which KM runs a macro (which is just key command) that copies the Task Name and then uses RegEx to separate words and remove some other characters etc. So all the data is pulled and generated from different sources and at the end it’s added to the Task List.

So I was going to run a macro once these other macros are finished, that takes all of the ‘temp’ data that is sent to the Task List, and stores it in a separate set of variables like I explained above - EACH time the Task Macros are run. So that each item in the Task List has it’s own set of 'semi-permanent" variables (that will only be overwritten every two weeks or so).

And finally, every two weeks I run a macro that takes all these “Tasks” and all their corresponding data and generates invoices from them - in Excel, probably by targeting cells in Excel with AppleScript and inputting the data that way. I suppose the main ‘issue’ is that I’d be relying on KM to ‘hold’ this data in Variables for 2 weeks at a time etc. (though the data would also be in the “Task List” file). Not that this should be an issue per se, but I suppose it’s not ideal since I’m working on 2 different machines throughout the week and so I’d need to sync up the Variables.plist between them in addition to syncing Macros.

I think Peter’s current solution will help me work through some of this now to help me determine if this way is preferred to just copying data out of the task list and then into Excel. I’ll be sure to update this post with any further questions, once I work through some of this.

Thanks again for the input

Perhaps this is an opportunity to reevaluate your workflow from scratch, from primary sources.
Sorry to keep repeating myself, but I really believe that it is in your best interest to start from the beginning, and detail your manual workflow steps. If you really don’t want to do this, just say so, and I’ll quit asking. :wink:

As promised, in v8 there are Dictionaries which can contain this sort of structured data.

1 Like

Hi Peter,

All the new stuff in v8 looks great and exciting, so thank you!

Regarding the Dictionaries and in reference to my first post above, could you speak to any advantages you can see to using Dictionaries vs. below. Basically, after I write the first set of data into the 'Item1' variables, I increment the Index and start using 'Item2' next time.

Also, depending on how exactly I go about manipulating this data in the 'next step', the one thing I can foresee as being useful would be the ability to say something like "If Item%Variable%Index%Project" is "Vegetables" (some 'Items' will have the same "Project" value / in this case Vegetables) then 'do this' - where %Index% would actually have to reference ALL the 'Items' regardless of what index number they have; so Item1Project, Item2Project, Item3Project, etc. - instead of having a bunch of 'If' statements checking each individual 'ItemXProject' to see if it's "Vegetables".

Thanks!

I too would like to see how @peternlewis would set this up.

A few thoughts, mostly based on using JavaScript arrays and objects (which are like dictionaries):

  • With your approach you have a bunch of unrelated variables that you have no direct means of searching or sorting based on contents.

  • There are (or at least were) some KM Actions that don't accept indirect reference like %Variable%%%Variable%Index%%%Project%

    • Plus all of those % marks make it hard to read, and hard to type correctly
    • For example:
      • KM: %%Variable%%Item%Variable%idx%Project%%
      • JS: items[idx].Project
  • Your indirect variable approach mimics KM Dictionaries to a certain extent, but I suspect not a fully featured.

  • I don't know what the input/output for KM Dictionaries is, or will be, but I hope at some point there will be something like JavaScript JSON.parse() and JSON.stringify().

As I mentioned earlier, a lot depends on how you want to use the data after you get it into KM. I'd suggest that you develop a prototype/proof-of-concept model with limited data before you expend lots of effort on any one approach.

Compare Dynamic Variables with KM8 Dictionary

@peternlewis, please improve if you can. This is my first Dictionary.
Key Issue: How to Model Array of Dictionary Objects

Example Results

Unable to Directly Display the KM Dynamic Variable
%%Variable%%Item%Variable%idx%Project%%


###MACRO:   Dictionaries vs Dynamic Variables (Indirect Ref)

~~~ VER: 1.0    2017-09-20 ~~~

####DOWNLOAD:
Dictionaries vs Dynamic Variables (Indirect Ref).kmmacros (7.1 KB)
Note: This Macro was uploaded in a DISABLED state. You must enable before it can be triggered.


Firstly, you can iterate through the dictionaries and through a dictionaries keys.

You can think of Keyboard Maestro as basically having a table of triplets: dictionary, key, value. You can the Set Dictionary Value action to set an entry from those three things.

I would be temped to use the Index variable as the dictionary name itself, then. Then the keys would be simple strings. So things like:

Then you could iterate through the dictionaries, restricting it to ones that start with "Project" and do something like:

Peter, I’m not following you.

I think we need a complete example for everyone, one that we can put into the Wiki.

I don’t see your iteration?

The whole thing would look like this. For dictionaries named "Project37", with key Project mapping to the name of the project, in this case Vegetables.

I am actually using dictionaries for a few things, but there's something important I still don't get. I can set them, I can retrieve them, I can even loop through them. This took me dozens of hours of work to achieve because I'm dumb and because of the lack of clear examples in the documentation, and the forums, and the internet. I'm starting to understand, but there's an important thing I still don't get. To show you what I know, let me start by saying that I can fully understand what these actions do:

It sets, then gets, and then speaks the key names and values of those keys in that dictionary. That's great. (It took dozens of hours of work to get to this point, mostly because it was not obvious how to create a loop for dictionaries.)

But in some (most?) of the examples on the forums there are strange character sequences that I don't understand, like this one:

When I copy that action, character for character, and then activate it, it never enters the body of the loop, even though the dictionary is set with some values. Is the example supposed to work? Can someone explain the ENTIRE content of the box in the middle of the action? This is an example from the forums but it does NOTHING and it has a completely non-obvious, complicated, an unexplained text box in the middle. If this is supposed to do anything, I'd love to know what it does or what it was intended to do. It looks crazy because the variable in the "For Each" box above it also is used in the text box in the middle, which seems like circular reasoning. And as written it NEVER EXECUTES the actions below it.

No doubt I'm dumber than Homer Simpson and someone can explain what I'm missing here.

It looks like I'm the one who inadvertently confused you here, since that was my example and I clearly made a mistake. Sorry about that; I don't have much experience using dictionaries myself, and I didn't have a lot of time to spare when I wrote that example, so I went off my experience referencing other variables in For Each and that turned out to be incorrect in this case. I was also confused by the collection being described as "the dictionary keys", which made me think I needed to reference the top key variable instead of its dictionary (in retrospect, it would have been clearer to me if this collection was instead labeled "the keys in dictionary:")

To answer your question, the syntax used in that middle box is used to reference a particular dictionary key in a standard KM text field, as you demonstrated yourself in your example that showed how to speak a given key value. However, in this middle field's case, despite it having a T icon that indicates it to be a standard text field, it is clearly not a standard text field, and is only meant to reference a dictionary name, which you also made clear in your example. Basically, my example should have been this:

Sorry again for my mistake that caused you frustration. I agree, the documentation for dictionaries and keys is definitely lacking, and I hope it can be remedied in good time. Actually, now that I think about it, can I ask what it is you're using dictionaries for? I know I'm not the only one who's still unclear on how or when to use dictionaries for their own use cases, so if you could share why you're using them, that might serve as helpful documentation in its own right.

Hmm, that gives me food to think about. I'll work on your post for a while to see if that illuminates me. You did ask me a question. You asked me what I use dictionaries for. I will answer that here. My programs use lots of strings. Let me create this example: (it's a contrived example to illustrate the issue more clearly)

You can see why I need the Ruler for this, because lining up text fields with tabs is very helpful. I also posted recently about a bug related to the ruler.

Then, because code looks clearer with commas rather than tabs, I use an action to replace the tabs with commas. Technically it's not required but I think it makes some of the code look cleaner so it probably helps clarify what follows below.

Then for the magic. I loop through the lines of this "database" and create several dictionaries as follows:

Once I've done this I can convert any item from one column in the table to the other. For example, if my program wants to convert a country abbreviation to its full name, I would do this:

Of course the name I'm converting doesn't have to be hardcoded, it can be a variable:

This saves me lots of time. Typically in the past I would achieve this with SWITCH/CASE actions, to perform the conversion, something like this:

But that was getting hard to manage and very repetitive. This seems to solve this issue for me.

Despite my successes, I still don't understand the weird syntax used in that one field. You made an attempt to explain it, and I will try again to understand. It may take me a few hours or more.

1 Like

Thanks for the in-depth example! That does seem like a good use-case for dictionaries, and I’m glad they’re proving useful for you. That said, I’m confused about what it is you still don’t understand regarding the dictionary syntax even after making considerable-seeming use of it. You clearly understand that in KM, text within percentage symbols is used to reference tokens, and you’ve also clearly figured out that to access a given dictionary and key you need to do so within the %Dictionary% token using brackets and commas like so:

%Dictionary[DictName,DictKey]%

So since you understand all that, I’m honestly not sure what could still be giving you trouble. In case it’s any help, I can point you to the KM wiki’s page on variable arrays, since dictionaries are essentially a special kind of array and the syntax is very similar: https://wiki.keyboardmaestro.com/manual/Variables#Variable_Arrays

If that link doesn’t help answer your question, can I ask what it is specifically you still don’t understand? I can’t promise I’ll be able to explain what you’re running up against any better than I already have, but if I know exactly what’s confusing you I can at least give it a try.