.. _python-dictionaries: Python Dictionaries ################### .. wordcount:: .. vim:ft=rst spell: We introduced python lists as a nice way to store multiple items in a single container. This is a powerful way to expand the size of the data set your program can manipulate. There is one problem with lists, though. They are ordered by how items are placed in that list, and the only way we can access items is to use an integer index to locate an item. Early programmers found many clever ways to deal with data stored this way. However, Python has yet another neat way to store data: dictionaries! What is a Dictionary? ********************* That is easy, it is a book ordered using words. When we locate a word, we find data about that word. Hmmm, this sounds useful. As an example of a problem I have to solve, let's see if we can create a way to track a bunch of small computer boards I use for one of my classes. I have several basic boards, and many of each one, so I can use them in lab projects. Here is a starting list: * Arduino: * Uno: 20 * Leonardo: 3 * Raspberry Pi: * Model B: 6 * Model 2: 10 * Model 3: 4 * Teensy: * 1.4: 5 * 2.0: 15 * 3.1: 4 Boy, do I have a lot of tiny computer systems! They are fun to experiment with! That is enough to show the problem. How to Store the Data ********************* I need to track the board name, model number and quantity. I suppose I could just put those three pieces of data into a list, and add one boards list to another list tracking all my toys. Something like this: .. code-block:: python toy1 = ['Arduino','Uno',20] toy2 = ['Arduino,'Leonardo',3] toy2 = 'Rspberry Pi','Model B', 6] toys = [toy1, toy2, toy3] And so on, you get the picture. This will work, but finding information will be messy. There is no way to see if I have a particular board without searching this two-dimensional list. Let's try to use one of Python's dictionaries to make it easier to locate boards: Creating Dictionary ==================== We can start off by building an empty dictionary, it looks like this: .. code-block:: python toys = {} Nothing special there, it is like an empty list, but we use curly braces. I am going to store my board data using the name of the board as an "index". Except here we call it a "key", and a key is a string: .. code-block:: python toys['Arduino'] = {} Hmmm, it looks like I am going to put a dictionary inside another dictionary. Yep, I want to make it easy to find the model of each board: .. code=block:: python toys['Arduino']['Uno] = 20 Wow, that looks like a two dimensional list with strings as indices. It is almost that, but not quite. Here is all of that data above, planted in a single Python dictionary: .. literalinclude:: code/toys.py :linenos: And here is what this code produces: .. code-block:: text $ python3 toys.py {'Raspberry Pi': {'Model 2': 10, 'Model B': 6, 'Model 3': 4}, 'Arduino': {'Leonardo': 3, 'Uno': 20}, 'Teensy': {'2.0': 10, '3.1': 4, '1.4': 5}} {'Leonardo': 3, 'Uno': 20} 20 Dictionaries are not ordered ============================ If you look at that output, you notice that the data is not stored in the order defined by the code. Python use clever schemes to set up a dictionary to make it easy to locate items based on the key string, so we cannot depend on the order. If we want to produce a (ugly) listing of our toys, we can do this: .. literalinclude:: code/toys2.py :linenos: :lines: 20-22 And we get this: .. code-block:: text Raspberry Pi {'Model 2': 10, 'Model 3': 4, 'Model B': 6} Teensy {'3.1': 4, '2.0': 10, '1.4': 5} Arduino {'Leonardo': 3, 'Uno': 20} I would really like for that list to be in alphabetical order: .. literalinclude:: code/toys3.py :linenos: :lines: 16-22 This works, and we see a nice way to sort a list as a bonus. Here is the final block, producing a neat listing: .. literalinclude:: code/toys4.py :linenos: :lines: 16-25 Here is the final display: .. code-block:: text Arduino Leonardo : 3 Uno : 20 Raspberry Pi Model 2 : 10 Model 3 : 4 Model B : 6 Teensy 1.4 : 5 2.0 : 10 3.1 : 4 Not bad! Searching for a key ******************* Now, suppose we need to see if we have a particular board. Here is how we might do that: .. literalinclude:: code/toys5.py :linenos: :lines: 16-22 Notice the simpler way to loop over the keys. This happens so often, e just need to ask if the key is in the dictionary! Here is the output: .. code-block:: text You have 20 Arduino Uno boards Short Circuits ============== This "if" test is an interesting pattern It asks two questions, in a particular order. Since I am using an "and" operator, if the first question returns "False", there is no need to ask the second question, and Python will not ask it! This prevents an error if the "board" key is not found. This pattern is often used to prevent the code from doing something silly, like dividing by zero. .. code-block:: python if b != 0 and a/b > 5: pas I am not sure what is going on here, but the divide is safe, since if "b" is zero, the first question returns False and the second question is not asked at all! Handy Sorting a Dictionary ==================== Well, we are not really going to reorder things in the dictionary. Instead, here is how you can print out the items in your dictionary in sorted (by index) order: .. code-block:: pythpn keys = list(mydata.keys()) keys = sorted(keys) for k in keys: print(k,my_data[k]) See how this works. That ``keys()`` method returns a list of the keys being used in the dictionary. The ``sorted()`` function rearranges that list, giving you the index values in alphabetic ordr. We then loop over that list to print out the dictionary data! Wrapping up *********** Dictionaries are a powerful way to manage data. You can build database like code to track all kinds of things, and find the data easily by using hem. Your next lab project will ak you to analyze a famous speech, and find out how many different words are in the speech, and how often each word is used. A dictionary will be a great place to do tat work!