How to use Dictionaries

Peter, this is exactly my problem, I don’t see how Dictionaries might be useful :persevere:

Well, that’s ok then. Don’t worry about it. If you don’t have a problem to which dictionaries are the solution, then there is no point trying to use them.

There have been occasional forum questions for which dictionaries might be a helpful solution. Such as if you have a set of projects, and each one has a name and folder and client and email address, you can just switch one variable and use dictionary lookups to find the appropriate info.

But it’s not a tech that is going to be useful in too many cases.

2 Likes

Many of my macros rely on a csv, which is read-in at the start of a macro. The macros then do a look-up of this csv and populate a number of variables.

My feeling is that dictionaries might handle this kind of thing, but given that:

  1. I have already written the macros; and
  2. the CSV is very easy to amend and update (which happens every two-three weeks when I have a new assignment)

I haven’t looked in them just yet :slight_smile:

Thanks Peter, it’s a little bit clearer now :+1:

I wonder whether the phrasing of the Wiki entry might become clearer with a slight adjustment of number ?

At the moment, the opening overview in

manual:Dictionaries [Keyboard Maestro Wiki]

explains that:

A dictionary is a mapping from a key name to a value

but might that not prove a bit confusing ? It sounds rather like one name and one value – which would be puzzling – not very obviously different, at first reading, from a Keyboard Maestro variable ...

In fact, of course, a dictionary is not a single key name -> Value mapping, it is a named collection of different key -> value mappings.

Classic examples of dictionaries might be a named menu, with a set of menu item label -> menu item value mappings or a named group of addresses, with a set of names mapped to address details.

Perhaps the opening phrase could be edited to something like:

A dictionary is a named set of mappings from key names to corresponding values

(AppleScript records and JavaScript dictionaries might also be recognisable analogues to some readers, of course)

{ "alpha": 1, "beta": 2, "gamma": 3 } etc

(otherwise known as a name-space, or a set of names for values)

3 Likes

I’ve adjusted the wiki page.

1 Like

I use dictionaries frequently in Python. Given that perspective, I’m trying to understand the syntax for their use in KM.
Here’s an example:
I have created a dictionary in KM, by using a stock ticker as the key and the value as the URL to stock research for that ticker. <key=abbv> – <value=https://research.investors.com/stock-checkup/nyse-abbvie-inc-abbv.aspx>
I want to roll thru this dictionary, opening each URL, processing the HTML page text, and associating that data with the ticker.
I’ve got a lot of this working (in Python), but I need to work with the dictionary in KM to wrap the whole process.

in python, it’s
for thekey in thedict.keys():
do_stuff with thedict[thekey]

how does this work in KM?

Thanks!

In KM, this is handled with a For Each action and a dictionary keys collection:

2 Likes

I don't know about Python, but in KM Dictionaries do not support arrays, and KM does not have traditional arrays. So it becomes complicated in KM. You would have to create a separate KM Dictionary for each stock (named Stock1, Stock2, ...), and all of them would have two keys: Symbol and URL.

So, here is an example macro that will generate a list of all stocks, the Symbol and URL for each:

@peternlewis, if there is a better, simpler, way of doing this, please educate all of us.

##Macro Library   Dictionary Test @TEST


####DOWNLOAD:
<a class="attachment" href="/uploads/default/original/3X/2/a/2aeac4870b31de9740b1e95c5cbdace4f9e5e18d.kmmacros">Dictionary Test @TEST.kmmacros</a> (7.4 KB)
**Note: This Macro was uploaded in a DISABLED state. You must enable before it can be triggered.**

---

### Example Results

<img src="/uploads/default/original/3X/4/5/451dcc21f42e05ae50829848b430c68d980b8b0a.png" width="362" height="283">

---

<img src="/uploads/default/original/3X/9/0/9043ab2146b61a16fc59e49b3d54c92ac2d81237.png" width="469" height="1697">

Frankly, I would never use KM for this use case.  I'd use JavaScript (in a [Execute a JavaScript For Automation action (KM Wiki)](https://wiki.keyboardmaestro.com/action/Execute_a_JavaScript_For_Automation), where it is _very_ easy and compact to define an array of stock objects, and to search, select, sort them.  But then I'm still struggling with how to use [Dictionaries manual (KM Wiki)](https://wiki.keyboardmaestro.com/manual/Dictionaries).

I solved it, once I understood the syntax.
First I created the dictionary with the tickers and URLs.


Then I process.

I got a little stalled until I noticed it's %Variable, not %variable.

Thanks for the help!!

1 Like

Could you please post your macro just so we all will have a good example?

It seems very limited in that you are having to use the stock symbol as the key name, and then storing the URL as the value for that key. So the key name does not reveal any info about the nature of its value. This means you no way to provide additional keys about a specific stock, unless you use a kluge like naming the key as stockSymbol-keyword, as in "vz-URL".

1 Like

Hi JMichaelTX,

Creating the dictionary was a mostly manual process. I chose not to automate the creation of the dictionary, due to the IBD website's wonky research page. Even so, it was a cinch to create the dictionary. I just use the Set Dictionary Action, fill in the ticker, go to IBD and fill in the ticker there, and hit the Get Stock Checkup button. After I hit that button, the page redirects to the URL for that ticker. Granted, scripting this in KM is relatively easy, but IBD will misbehave after some number of tickers, and you have to kill the macro.

So,

  1. Create a macro (pictured in a previous post)
  2. insert a Set Dictionary action
  3. fill in the dictionary field with "stock_tickers"
  4. Fill in the key with the stock ticker
  5. Fill in the URL with the URL you get from IBD
  6. Create a new Set Dictionary action, using the same name in the dictionary field, but a different ticker and URL. Repeat this step with all your tickers.
  7. When done adding your ticker actions, save and run the macro

You end up with one dictionary, holding some number of tickers with their associated URL.

set stock dictionary values.kmmacros (6.9 KB)

You could either have multiple dictionaries, eg a Symbol dictionary and a URL dictionary, or you can have compound keys "key1.symbol" "key1.URL".

1 Like

Thanks, Peter. I like that approach the best.

Hi all,

The solution I came up with solved my issue perfectly, in the simplest manner. Given the additional discourse here, I may not have stated my issue clearly enough. My solution was simply a means to an end. KM allowed me to elegantly solve a piece of a larger project, which is Python based.

But I’m still thinking about the conversation here, trying to figure out what you’re trying to solve.

I believe you’re trying to add more data to the value part of the dictionary. As mentioned, the key.URL, key.symbol, key.other_stuff could work. Seems somewhat unwieldy to me. If you need additional data in the value, why not make the value another dictionary? That value could look like this:
{“stock_name”: “Toronto Dominion”, “market_cap”: “$68,000,000”, “dividend_yield”: “3.9%”} I’m doing something like this in my Python project. I use the URLs to nab the HTML source for each ticker, and parse that HTML for the data I need. The data elements go into a Python dictionary which has about 40 elements.

I find working with dictionaries easier in Python than KM, but I’m more familiar with Python. I’m excited to see dictionaries added to KM. KM is a really useful tool.

Generally speaking, one dictionary object contains all properties for the given target object. So if my target is stocks, then one dictionary object would be for one stock, and it would include all desired properties of that stock: symbol, name, company, rating, URL, etc.

The complication is that you want to associate the dictionaries for all stocks together.
In JavaScript, you can create one variable which is an array of objects, and then search, sort that array on any object property. Since KM does NOT support arrays, we have use other schemes, such as the ones that @peternlewis described.

IMO, KM dictionaries work well for simple use cases. If you have a complex use case, and know how to use dictionaries (objects) in other tools, then the other tool (Python, JavaScript, etc) may be a better tool to use. It's up to you.

The tool features missing from KM Dictionaries that could be important are search and sort.
Yes, you can do a search by using a For Each Action to loop through all dictionaries and then a If Then to find the ones that match. But then what? You can't get an array of found dictionaryies, so you have to extract the properties of the object you want, and then store them somewhere. But where? . . . so it gets complicated and verbose quickly.

There is no sort in KM. So you'd have to extract the properties to sort on into a text list, and then use another tool, like Bash sort, to sort the data.

As always, I try to use the best tool I know how to use for the job. So, it might be KM in some cases, and JavaScript in other cases; or even ASObjC, which has very powerful dictionary tools.

But this is just version 1 of KM Dictionaries. Who knows what additional features @peternlewis has planned for us. :smile:

Not to drag this on too long...
KM supports arrays and has for quite some time.

No, that's not what I want.

What I want is to associate all my stock tickers with an associated URL. That's ALL. And I achieved that. Problem solved.

If I did want KM to create a record (or struct, or array, if you prefer) I could do that. Just generate a dictionary named with my ticker as the key, and have its value be another dictionary which holds all the key/value pairs holding related info. I would then have a dictionary of dictionaries. I could also have an array of these dictionaries like what you describe. KM makes it relatively easy to get an array of keys, or an array of values, or both from a dictionary. I could then get an array of keys from the dictionary, sort it, and use that sorted list to grab the values from the dictionary. But that's not what I wanted.

And to clarify things a bit, a dictionary is not an array. The Python dictionary definition is similar in other programming languages: "A dictionary is an associative array (also known as hashes). Any key of the dictionary is associated (or mapped) to a value. The values of a dictionary can be any Python data type. So dictionaries are unordered key-value-pairs." This definition applies to KM.

JavaScript doesn't have a structure called a Dictionary, but it has Associative Arrays: "...sometimes this is called a hash or map structure or a dictionary object. An associative array is simply a set of key value pairs." Nothing magic here. KM's Dictionaries are key/value pairs.

Regardless, I'm not writing my project in KM, I'm writing it in Python. KM is just a very handy tool to get some of the work done.

Sorry, but those are pseudo arrays, not true arrays that could contain any data type, like dictionaries.

I understand that. But you asked:

That is the question/issue I was addressing. It is how to use Dictionaries for the more general use case.[quote="thebroz, post:21, topic:8183"]
If I did want KM to create a record (or struct, or array, if you prefer) I could do that. Just generate a dictionary named with my ticker as the key, and have its value be another dictionary which holds all the key/value pairs holding related info. I would then have a dictionary of dictionaries.
[/quote]

That would be great! Please show us a real example of how you would do this.

I never said it was. My example used a JavaScript Variable, which IS an array, to contain multiple objects (dictionaries).

Having said that, if you consider a plist or XML as a dictionary, then a dictionary can in fact contain arrays:

Consider this example (extract) taken from the KM macro plist file, which is a XML file:
Note that there is a top level <array> which contains an <dict>, which in turn contains an <array>.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array> <!-- START OF GROUP LIST -->
	<dict> <!-- START of GROUP 1 -->
		<key>Activate</key>
		<string>Normal</string>
		<key>CreationDate</key>
		<real>461048205.02807498</real>
		<key>CustomIconData</key>
		<string>KMEP-Burning</string>
		<key>Macros</key>	
		<array> 
			<dict>	<!-- START OF MACRO 1 -->
				<key>Actions</key>
				<array>	<!-- START of Action List for Macro 1 -->
					<dict>	<!-- ACTION 1 of Macro 1 -->
						<key>MacroActionType</key>
						<string>SetVariableToText</string>
						<key>Text</key>
						<string>Set in the calling Macro.</string>
						<key>Variable</key>
						<string>SingleLine</string>
					</dict>
				</array>	<!-- END of Action List for Macro 1 -->
				<key>CreationDate</key>
				<real>530147101.03176898</real>
				<key>ModificationDate</key>
				<real>534223708.42322803</real>
				<key>Name</key>
				<string>Execute Macro Parameter</string>
				<key>Triggers</key>
				<array/>	
				<key>UID</key>
				<string>14A0A5C7-58FE-4FEF-B4AC-6212DB0E7736</string>
			</dict>  <!-- END OF MACRO 1 -->
		</array>
		<key>Name</key>
		<string>[TEST]</string>
		<key>ToggleMacroUID</key>
		<string>40691C77-9FA8-43B0-A4FA-80F6664A217A</string>
		<key>UID</key>
		<string>5FC1DC16-E27C-4EBC-9869-9B705B73EAE1</string>
	</dict>	<!-- END OF GROUP 1 -->
</array> <!--> END OF GROUP LIST -->
</plist>

JavaScript DOES have objects, which can be key/value pairs. Same thing as a dictionary. I use them all the time.

Which is fine. As I said above, use the best tool (you know how to use) for the job.

Currently, the only way to interact with dictionaries is via macros? This is not ideal. Would it be possible to build in a dictionary editor similar to the variable viewer like found in the preferences menu?

You should take a look at @DanThomas’s excellent macro: