Dictionary Patch-of-the-Day (POTD) Thread
So, for the next seven days, my colleagues and I will be putting up dictionary-based patch-of-the-day posts in this thread. It's been my feeling that we've not shared enough of our own use of dictionaries - or the way that dictionaries have changed the way we work. So here's a challenge: take our POTD patches, try them out, and see if you can find a way to use them in your own work.
DAY ONE:
To start off, I'm going to show off a simple little patch that shows the use of dictionaries with the same name - and how this allows sharing of name/value pairs across all of the boundaries that Max presents. You can use them in a patch, in a bpatcher, in subpatchers and even in completely separate patcher files. This gives you the ability to segment your patches in whatever way makes you feel most organized, but also gives you the name/value pairing that helps your patches be self-documenting.
But an addition advantage is seen in this particular patch: the dictionary acts as a temporary storage spot for data coming from various locations, and I only have to use the data when I see fit (in this case, whenever I'm about to fire off a new note). This can save me the hassle of storing a lot of data in messagebox objects or other temporary variables, and allows me to have parameter generation at whatever rate is useful.
Enjoy this basic-but-useful patch, and I'll catch you tomorrow with another!
[ddg]
Nice one, I've always wondered how to use dictionaries properly so will definitely taking part in this challenge (after my I hand in my dissertation) Thank you :)
Is it weird that I read all of your forum posts in your voice now?
Such a lovely pedagogical cadence.
This is handy, as I've not taken the time to figure out the whole dict thing in terms of my own patching.
Thanks, I also have been slow on the uptake of dict so this is a good kick in the pants!
Great idea Darwin, looking forward to the full series!
DAY TWO:
One of the values of storing things in dictionaries is that saving and restoring the content is quite simple. Similar to working with coll, you can add a file name to the dictionary to have it auto-recalled when you open the patch. The example patch does just that in the first (top-most) example, restoring the 'best-henry' and 'worst-henry' values that were most recently saved.
In the second (middle) example, you can change the content, then use the export command to save the contents to specific file names. You can either using the "export" command directly to bring up a dialog for saving, or add a filename to the export command to cause a silent save. The "import" command allows you to bring in previously saved results (and again, you could add a filename to silently import a previously saved file).
The last (bottom) example helps you auto-save your dictionary contents; by using the closebang object, you can force the system to save the contents of the dictionary when you close the patcher file. This means that you (or your patch user) doesn't have to explicitly saved the dictionary when they are done with their work. Handy!
Another relatively simple example, but one that shows the dict object as a useful and self-documenting alternative to coll in many applications.
[ddg]
Rodrigo,
I do the same thing! Unfortunately, my family doesn't think that my readings of my own blog posts are very interesting...
[ddg]
Nice, i look forward to seeing more. Hope you cover some things about nested dictionaries and a good way of pulling data from deeper hierarchies. Or querying hierarchies. Like if I were to have a dictionary that stores all the information about a fitness center, and some of my top-tier keys were: MemberID, Equipment, etc., and then I wanted to find out information about each tier sequentially (in case I don't know how the data is stored).
I created two examples of how i'd do it, the second patch is a slightly different version of the first but features a recursive [umenu] that makes it a little simpler/smaller/efficient and infinitely scalable, whereas the first patch, you're able to clearly see which tier you're on and its parent tiers but you have to copy and paste a new [umenu] sub-category section for every new tier. I'm sure there's a way to combine them for best efficiency and clarity, but i'll wait on solving that in case you have better methods of going about this. cheers.
I also attached an example dictionary in case you wanted a quicker way to test my examples instead of having to create entries yourself.
And I started working on this before I saw Greg's message...
DAY THREE:
Data structure design is a big part of many programming tasks - important enough that many books have been written about the subject. In today's POTD, we are going to look at some of the ways we can create deep data structures, and also how to access the data once it is properly stored.
In the first section, we store simple contents of various types, and can click on the button to see the hierarchy displayed in the Max window. If you double-click on the "basic-data-access" subpatcher, a new window will appear that shows some ways to access data once it is stored in a dictionary (note: I take advantage of the @embed 1 flag for this example). In addition to getting a key's value, I can also get its type - and can get a list of all the available keys should I want to put them in a menu, or perhaps iterate through all of the keys.
Returning to the main patch, the second section covers multi-value data: lists and arrays. You can initialize both by sending them content in list format; the only differential is the use of the "[]" identifier behind the array. However, if we look within the "multi-value-access" subpatcher, we can see that both arrays and lists can have their contents accessed by a 0-based index. We can also see here that the dict.view gives us a nice view into the data whenever we click on the button.
The final section of the main patch deals with heirarchical data, which is accomplished through the use of sub-dictionaries. The documentation isn't really clear on how you create a sub-dictionary within a dictionary - but the trick is found in the use of the replace message, which will create any part of the hierarchy that doesn't exist. It also uses the "::" separator to delineate each level of sub-dictionary that is in use. Therefore, the key "this::that" would look in the current dictionary for a sub-dictionary called "this", and would refer to the key "that" found within the sub-dictionary. You can go as many levels deep as you like, although things like "this::that::the-other::thing" would get a little irritating after a while...
One cool hint is shown in the bubble-comment: you can always get a deep overview of the dictionary's content by double-clicking on it; this will display the contents of the dictionary in JSON format - a great way to eyeball all of the stored data.
I hope this was useful; please let me know if there are other things you'd like me to explore!
[ddg]
I wish there was an additional argument for "getkeys" that could output the keys of a subdictionary. The whole sub-dictionary thing is kinda confusing anyways, is it defined this way because that's how JSON/XML calls it? I'd rather call it subkeys or something. So for example, in your multi-level-access subpatch, is there an easy way to dump out all the (sub)keys [field-a, field-b, field-c] of the dumpster key? the only way I know is to redefine the [dict] object as the dumpster sub-dictionary, and then all those (sub)keys now become the top level keys.
it'd be nice for a message like "getkeys dumpster" and out the third outlet you get: field-a, field-b, field-c.
DAY FOUR:
Today, I turn the mic over to Gregory Taylor, who uses the dictionary output from collisions in the physics engine to get a bit musical. Here is his explanation:
For this patch-a-day, I wanted to create a very simple patching example from the Max world where dictionaries are actually in use in as a part of Max itself – the jit.phys world.
This patch creates a number of objects using the jit.phy.body object: six square planar objects arranged to form the outside faces of a cube, and a sphere that is located inside of the cube. Each of the jit.phys.body objects is given a unique name, which we’ll be making use of.
The object named ball is special. Unlike the other bodies, this one has attributes set that define how it will physically interact with the “walls” of the cube (damping, friction, restitution, mass, and – most importantly, it has its collisions attribute set to 1. When we do that we enable the use of a dictionary that contains information about collisions between objects.
The ball can be set In motion using the button > impulses subpatch. Since we have enabled collisions in the physical world, a dictionary containing collision information is output from the rightmost outlet of the ball jit.phys.body object.
Inside the collision_detection subpatch, we use standard Max message processing and routing objects (zl.slice, and a very elementary use of the regexp object) to sort through the information contained in the collisions dictionary once we’ve used the handy dict.iter object to cut the directory up into separate messages (similar to the way that we use jit.spill to convert a matrix into a list).
The result? We get a nice bang any time our ball makes contact with any of the six surfaces.
I’m using those bangs to trigger one of six sequences sequentially as the ball caroms around inside the cube. Since I have been thinking recently about the Prince's untimely death, I elected to grab a few fragments from one of my favorite Prince songs for use as my sequences (that’s also why the ball is purple).
... and here is the patch ...
Enjoy!
DAY FIVE:
For another weekend distraction, Ben Bracken has provided a peculiar patch: you paste in a compressed Max patch, and using the magic of a little regexp and the dict.deserialize object, decompresses it into a dictionary. What would you use it for? I dunno - but it does show you the process of combining text manipulation with the dictionary object to parse and access the underlying data in unique new ways.
Enjoy!
[ddg]
Woah, actually pretty cool, and ya not quite sure what i'd use it for. You can also go the other way around and use [dict.serialize] to put it back in the compressed form.
DAY SIX:
Every time I see Tim Place do something with the plot~ object, I'm reminded how cool it is. Then, of course, I forget all about it. Recently, I needed to do some running visualizations, and I wanted to have it look better than the output of multislider provides. Then I (finally!) remembered Tim and good ol' plot~.
One of the cool things about plot is that it can be fed by either lists of numbers or dictionaries. And if you use dictionaries, you can embed all of the display characteristics as well as the data that is used for the display. The result is a beautiful visualizer that is easily modified (or whose state could easily be saved in a JSON file), reasonably reactive, and pretty cool.
This example uses the bucket object as a shift register, and creates a running visualization of a drunk object's output. You can imagine all sorts of variations on this, and you can also see that clicking on the edit message to plot~ gives you some insight on the dictionary that plot uses internally for its state and display management.
Enjoy!
[ddg]:
please let me know if there are other things you’d like me to explore!
Array of dicts, please!
DAY SEVEN:
Another object that is able to deal with dictionaries for setting control is a secret weapon of mine: the live.step object. This object gives us everything we need to create interesting sequencers that implement a piano-roll interface, and includes sub-sequencer/editors for velocity, duration, additional parameters (if we need them) and even multiple sequences.
In this example, I've made a little performance system that allows you to change the current sequence (and the currently displayed edit function) with the number keys on your computer, allowing you to perform realtime quick-twitch switching. It uses the built-in standard MIDI playback on your computer, so you don't even need a MIDI device handy. But the dictionary trick here is the save and restore of the sequence data: you can save and restore (as well as manipulate, if you desire) the data using a centralized dictionary, with the contents saved as a standard JSON file. When you first open the patch, it always loads the default.json file.
This should give you some interesting ideas - like manipulating the JSON file with other programming tools, manipulating the dictionary's contents whenever you restore the data - or even manipulate it with a new button press. Since all of this information is stored in this easy-to-manage data system, the whole sequencing set is yours to mess up!
Enjoy!
[ddg]
Very useful thread, thank you for that - now I can at last see the value of dictionaries.
By the way, a series named Templates-and-Styles Patcher-Of-The-Day would be quite useful too.
Thank You Darwin for this patch a day series.
It’s been extremely useful!
ive just spent the last week working with dict, json and maxurl for the first time, figuring it out through trial and error. and now i find this thread! haha.
could anyone tell me if i would save much CPU by having 102 sub dictionaries in a single dictionary as opposed to 102 individual dictionaries. i couldnt figure out how to make the sub dictionaries, so i now that i have made all 102 is there any benefit in restructuring them into 1?
thanks for the great patches Darwin!
Is it too late to say thanks for all of the wonderful dictionary examples?
I hope not.
Thanks!
Thank you! I spent 24 hours trying to understand how to access data in sub-dictionaries, and your explanation solved it. I can finally go have some sleep.
I was trying to figure out how to set some parameters after loading .json file to a dictionary. I sat on it for hours and then I came across this thread. I looked over all the patches and the very last one, Twitch Sequencer, solved the problem for me. Thank you so much Darwin, excellent series!
still learning from you all the time, Darwin. thank you <333
Favorited(and Thank You, Dan, for bumping it <3)