Any interest in Dictionary/Hash Table support?

I’m wondering about adding some sort of dictionary support to Keyboard Maestro for 7.0. I’m thinking of something that maps a (database,key) pair to a value (all plain text strings).

So the sort of facilities that it would entail would be:

  • A store of Dictionary:key:value
  • Action: Set Dictionary value
  • Action: Delete Dictionary value (same as setting it to empty string really).
  • Text Token: %Dictionary%db%key%
  • Collection: Listing all Dictionaries
  • Collection: Keys in a Dictionary.

That all would be relatively easy to do, but I’m not sure what actual problems it would help solve. I’ve occasionally wanted a hash table, but I’m not sure any macros I have actually written would benefit from this.

So if this sounds like something that would be useful to you, let me know what you would use this sort of thing for.

Thanks.

2 Likes

+1 for Dictionary/Hash Table support.
Would be great.

PS: And more examples in the help file.

Hey Peter,

I believe KM does not have its own sort routine.

Sorting list items, removing duplicates, and retrieving items are pretty common actions.

I usually retreat to AppleScript and the Satimage.osax when messing with lists.

-ccs

You’re correct, Keyboard Maestro has no particular sorting facilities (other than those built in to some of the collections).

What I really would like to hear about are particular examples of a macro you want to build that dictionary support would be beneficial for.

Hey Peter,

I frequently use text tables for lookups. For instance:

Email Address				Salutation
--------------------------------------------------
peter@stairways.com.au			Hey Peter,

Usually I use a freestanding text file table (for easy editing), and AppleScript plus the Satimage.osax’s regex for this.

Reading the text file into a hash might make some of these lookups a bit faster.

But I’ve spent a couple of decades balancing quick-access and ease-of-use with the solutions I already have.

-ccs

On Sun, Apr 19, 2015 at 9:15 PM, peternlewis < kmforum@forum.keyboardmaestro.com> wrote:

So if this sounds like something that would be useful to you, let me know
what you would use this sort of thing for.

A dictionary would be more natural for me for macros that do, for instance,
a series of text substitutions and much more compact than if statements for
selecting from a large suite of options. I see this making some long macros
considerably less unwieldy.

Or at least that's what it looks like in my head, which can be a strange
place.

c

I don’t have a specific example, but I think if we could use a dictionary or hash table with a new element that implements switch/case support that would be awesome and would open up new/easier branching strategies, even for the simplest of macros that have more than 2 paths. Nesting if/elses in the GUI can get confusing at times.

My reasons: Better working with lists/tables (sorting, memory consumption?, speed). I hope for better text substitutions, reading large files to KM.

I have to admit to knowing bupkus about dictionaries and hash tables, but seeing ccstone mention the Satimage.osax for AppleScript gives me a bit of an idea of what you’re talking about.

I find myself often working with large amounts of text (either in files or in clipboard contents) in the areas of sorting, filtering, finding/replacing, calculating, etc. I generally cobble bits together using Satimage.osax, Grep, Sed, Awk, pbpaste, pbcopy, and a bunch of other things I know next to nothing about.

If what you’re suggesting, Peter, would make it easier to do these things via Keyboard Maestro, then please consider this a +1 vote.

What I’m missing from this discussion, and what I’m really looking for is concrete examples of a macro you want to write that would use a dictionary.

I can certainly imagine the value in some sort of dictionary, but in order to know what I need to implement to actually make available as functionality, I need to know not just general ideas of what might be done, but specific macros.

For example, @ccstone mentioned a lookup mapping emails to salutations. OK, but unless I add a preference panal ala Variables/Named Clipboards, then it probably needs to be read in from a text file, and if that is the case, why both storing it in a dictionary? Why not just read the file (the only case would be where that was unacceptably slow, but even then it could easily be solved with a grep command on the text file). So that example, to me, argues to either: a) add a dictionary and do the extra work of adding the preference pane, or b) don’t bother adding the dictionary, but not c) add the dictionary without adding a preference pane. Option (a) is certainly doable, but it changes the amount of work significantly, so it affects my decisions.

So I’d like to see concrete examples of macros because a “dictionary” is such a generic concept. I use essentially a dictionary mapping for my article ➤ link blog mapping, for looking up all sorts of information about the blog (eg Twitter handle of the author). Essentially that’s the same problem/solution as Chris’ email ➤ salutation lookup.

Hey Peter,

What about adding a Search File Action?

That would save some steps for users.

Another thing that keeps me using the Satimage.osax is all occurrences.

I can find the first occurrence or all of them (to a list).

I also have a lot of control over where and how I search:

set <theResult> to find text <searchString> ¬
  in <textVarToSearch or File> ¬
  starting at <integer> ¬
  for <integer> ¬
  case sensitive <boolean> ¬
  regexp <boolean> ¬
  whole word <boolean> ¬
  regexpflag {"IGNORECASE", "EXTEND", "MULTILINE", "SINGLELINE", "FIND LONGEST", ¬
              "FIND NOT EMPTY", "DONT CAPTURE GROUP", "NOTBOL", "NOTEOL"} ¬
  using <returnString> ¬
  all occurrences <boolean> ¬
  string result <boolean> ¬
  syntax ("POSIX" | "POSIX_EXTENDED" | "EMACS" | "GREP" | "GNU_REGEX" | "JAVA" | ¬
          "PERL" | "RUBY") » Default: "RUBY"

One other thing. AppleScript records are awfully limited prior to Mavericks and Yosemite, but the advent of ASObjC has made them much more powerful - if not all that pretty to use.

I shall soon upgrade to 10.10.x, so I can play with those toys.

-ccs

Currently it is just Read File, then Search Variable, so its only two actions. As you know, I try to keep actions orthogonal, which sometimes means more actions, but each action is independent.

The For Each action can iterate through matches in a clipboard, variable, or indeed in a file.

Yes, obviously there comes a point where a scripted solution is required.

I haven't heard of them, so I don't know what they are or how they can be used, but I look forward to learning about them as you come up with more interesting scripts!

The macro I recently posted re: ScanSnap could be significantly streamlined with this feature.

Keyed dictionaries have proved (for me, at least) to be the single most useful feature of Javascript for Applications, particularly in combination with easy serialisation and parsing,

  • JSON.stringify()
  • JSON.parse()

and good introspection

  • Object.keys(dictionary) ( for a list of all the keys )

and iteration

for (strKey in dict) {
    // use the key 
}

Certainly sounds like something that could be a very powerful addition to the repertoire of the KM model and UI.

Was this feature ever implemented? I’m doing a dictionary / key lookup in the Workflow app for iOS to parse forecast.io weather data [link to workflow], and finding their implementation very straightforward and easy. I wouldn’t have the first idea how to do this with a Script. I’m thinking there are other APIs I could experiment with here to do the same thing.

At any rate, if this feature were implemented, I’d use it to parse forecast.io data in a variety of contexts.

FWIW, the basics with JS:

(the JSON string can be assigned to and retrieved from KM variables, and reawakened as ‘dictionaries’, ‘objects’,‘associative arrays’, 'namespaces, (whatever you want to call them), for further setting and getting of key ⇄ value pairs.

// Get/set value for key.

function run() {

    // All JS 'objects' even numbers and functions, are cluster of key:value pairs

    // you can:
  
  
  // 1. CONSTRUCT them directly with curly braces


    var dictionary = {
        mykey1 : 1.618, 
        mykey2 : [1, 2, 3]
    }

  // 2. set values for new or existing keys
  
  dictionary['newKey'] = 'New Jersey';
  
  // 3. get a value for a key

  var valueFound = dictionary['mykey2'];
  
  console.log('valueFound:', valueFound)
  
  // 4. ask what keys we have
  
  var lstKeys = Object.keys(dictionary);
  
  console.log('keys:', lstKeys)
  
  // 5. Serialize the whole thing to JSON
  
  var strJSON = JSON.stringify(dictionary);
  
  console.log('JSON:', strJSON);
  
  // 6. Bring it back to life from a string later
  
  dctLazarus = JSON.parse(strJSON);
  
  console.log('dctLazarus', JSON.stringify(dctLazarus));
  
  return dctLazarus;
}

No, it has not been implemented, though there are plenty of ways to do it via scripts.

Can you give the examples of exactly how you use the lookup? How do you set and get values.

With the Workflow app, I just use the built in functions, like so:

Open URL: https://api.forecast.io/forecast/APIKEY/LAT,LONG
Get Contents of page
Get Text
Set Variable: Dictionary

Get variable: Dictionary
Get Dictionary from input
Get Value for Key: "currently"   (part of the forecast.io API documentation)
Get Dictionary from input
Get Value for Key: "summary"  (again, part of the API)
Set variable: Summary

Basically, this returns the “summary” of the “current” weather at the Latitude/Longitude provided to the forecast.io API. What’s neat is that you can grab from the dictionary lots of different kinds of weather information: hourly weather forecast (instead of summary), daily forecast, weather at a specific time in the past, etc.

Your dictionary implementation is very welcome, and seems, in particular, a neat way to store a set of options for a script action, without over-populating the KMVAR list.

On the house-keeping and the deletion of whole dictionaries – we can do this straightforwardly through AppleScript and JavaScript – is that the best approach, or is there also a GUI route that I have missed ?

You can just erase all the entries in the dictionary with a For Each loop:

  • For Each variable Key in Keys of Dictionary “Whatever”
    • Set Dictionary “Whatever” key “%Variable%Key” to “”
1 Like