yhj-yyyk[k[[y-[p[yyyy[[p[[y[^^yyhyh[[[[X[h[hXhy-y[yNjnyWwp[[[_-yWVwp=Vh[yW-l|p[yh=-[-y-y-=[[y_-yyy[[ny_-y=[_nlhyNnj-y-[[;-y[yy|pyy[y|ppy[yy;yy[|pywpy[|pywpy[yyyywpKhljlVjVy}wpi[yylhzwhphy[[[[iBbfAAfrfBEEeDrEBfreCCAXW~~| 684649474VBCZ 64}5Z~~ 647647VC 89VBW~B 847755VW 6849VC~ 896VPW 68496V~C 84G7VBC 84G756V-~CC 686896VC 84966V~ 68496VBC 6964V~~ 6849498F55-~~CC 887G7G7F55W 65946V 5598}55ZBCWCZZZX

Dictionary.` Consider a language. Each word maps to a meaning. A book is a written work. A cloud is floating water. In a dictionary we map keys (words) to values (meanings).`Python dictionaries` are maps. With square brackets, we assign and access a value at a key. With get() we can specify a default result.`Get example.` There are many ways to get values. We can use the "[" and "]" characters. We access a value directly this way. But this syntax causes a KeyError if the key is not found. `Instead: `We can use the get() method with 1 or 2 arguments. This does not cause any errors—it returns None.`Argument 1: `The first argument to get() is the key you are testing. This argument is required.`Argument 2: `The second, optional argument to get() is the default value. This is returned if the key is not found.`Get, none.` In Python "None" is a special value like null or nil. We often use None in programs. It means no value. Get() returns None if no value is found in a dictionary. `None `none-python`It is valid to assign a key to None. So get() can return None, but there is actually a None value in the dictionary.`KeyError.` Errors in programs are not there just to annoy you. They indicate problems with a program and help it work better. A KeyError occurs on an invalid access. `KeyError `keyerror-python`In-keyword.` A dictionary may (or may not) contain a specific key. Often we need to test for existence. One way to do so is with the in-keyword. `In `in-python`True: `This keyword returns 1 (meaning true) if the key exists as part of a key-value tuple in the dictionary.`False: `If the key does not exist, the in-keyword returns 0, indicating false. This is helpful in if-statements.`Len built-in.` This returns the number of key-value tuples in a dictionary. The data types of the keys and values do not matter. Len also works on lists and strings. `Caution: `The length returned for a dictionary does not separately consider keys and values. Each pair adds one to the length.`Len notes.` Let us review. Len() can be used on other data types, not just dictionaries. It acts upon a list, returning the number of elements within. It also handles tuples. `Len `len-python`Keys, values.` A dictionary contains keys. It contains values. And with the keys() and values() methods, we can store these elements in lists. `Next: `A dictionary of three key-value pairs is created. This dictionary could be used to store hit counts on a website's pages.`Views: `We introduce two variables, named keys and values. These are not lists—but we can convert them to lists.`Convert `convert-python`Keys, values ordering.` Elements returned by keys() and values() are not ordered. In the above output, the keys-view is not alphabetically sorted. Consider a sorted view (keep reading).`Sorted keys.` In a dictionary keys are not sorted in any way. They are unordered. Their order reflects the internals of the hashing algorithm's buckets. `But: `Sometimes we need to sort keys. We invoke another method, sorted(), on the keys. This creates a sorted view.`Items.` With this method we receive a list of two-element tuples. Each tuple contains, as its first element, the key. Its second element is the value. `With tuples, we can address the first element with an index of 0. The second element has an index of 1.`Program: `The code uses a for-loop on the items() list. It uses the print() method with two arguments.`Items, assign.` We cannot assign elements in the tuples. If you try to assign rentItem[0] or rentItem[1], you will get an error. This is the error message. `Items, unpack.` The items() list can be used in another for-loop syntax. We can unpack the two parts of each tuple in items() directly in the for-loop. `In this example, we use the identifier "k" for the key, and "v" for the value.`For-loop.` A dictionary can be directly enumerated with a for-loop. This accesses only the keys in the dictionary. To get a value, we will need to look up the value. `Items: `We can call the items() method to get a list of tuples. No extra hash lookups will be needed to access values.`The plant variable, in the for-loop, is the key. The value is not available—we would need plants.get(plant) to access it.`Del built-in.` How can we remove data? We apply the del method to a dictionary entry. In this program, we initialize a dictionary with 3 key-value tuples. `Del `del-python`Then: `We remove the tuple with key "windows". When we display the dictionary, it now contains only two key-value pairs.`Del, alternative.` An alternative to using del on a dictionary is to change the key's value to a special value. This is a null object refactoring strategy.`Update.` With this method we change one dictionary to have new values from a second dictionary. Update() also modifies existing values. Here we create two dictionaries. `Pets1, pets2: `The pets2 dictionary has a different value for the dog key—it has the value "animal", not "canine".`The pets2 dictionary contains a new key-value pair. In this pair the key is "parakeet" and the value is "bird".`Result: `Existing values are replaced with new values that match. New values are added if no matches exist.`Copy.` This method performs a shallow copy of an entire dictionary. Every key-value tuple in the dictionary is copied. This is not just a new variable reference. `We create a copy of the original dictionary. We then modify values within the copy. The original is not affected.`Fromkeys.` This method receives a sequence of keys, such as a list. It creates a dictionary with each of those keys. We can specify a value as the second argument. `Values: `If you specify the second argument to fromdict(), each key has that value in the newly-created dictionary.`Dict.` With this built-in function, we can construct a dictionary from a list of tuples. The tuples are pairs. They each have two elements, a key and a value. `dict `dict-python`This is a possible way to load a dictionary from disk. We can store (serialize) it as a list of pairs.`Get performance.` I compared a loop that uses get() with one that uses both the in-keyword and a second look up. Version 2, with the "in" operator, was faster. `Version 1: `This version uses a second argument to get(). It tests that against the result and then proceeds if the value was found.`Version 2: `This version uses "in" and then a lookup. Twice as many lookups occur. But fewer statements are executed.`Performance, loop.` A dictionary can be looped over in different ways. In this benchmark we test two approaches. We access the key and value in each iteration. `Version 1: `This version loops over the keys of the dictionary with a while-loop. It then does an extra lookup to get the value.`Version 2: `This version instead uses a list of tuples containing the keys and values. It actually does not touch the original dictionary.`But: `Version 2 has the same effect—we access the keys and values. The cost of calling items() initially is not counted here.`Result: `Looping over a list of tuples is faster than looping over a dictionary. This makes sense—with the list, no lookups are done.`Frequencies.` A dictionary can be used to count frequencies. Here we introduce a string that has some repeated letters. We use get() on a dictionary to start at 0 for nonexistent values. `So: `The first time a letter is found, its frequency is set to 0 + 1, then 1 + 1. Get() has a default return.`Invert keys, values.` Sometimes we want to invert a dictionary—change the values to keys, and the keys to values. Complex solutions are possible. But we can do this with a simple loop. `Memoize.` One classic optimization is called memoization. And this can be implemented easily with a dictionary. In memoization, a function (def) computes its result. `Memoize `memoize-python`Memoize: Lower Dictionary `lower-dictionary-python`Once the computation is done, it stores its result in a cache. In the cache, the argument is the key. And the result is the value.`Memoization, continued.` When a memoized function is called, it first checks this cache to see if it has been, with this argument, run before. `If it has, it returns its cached—memoized—return value. No further computations need be done.`If a function is only called once with the argument, memoization has no benefit. And with many arguments, it usually works poorly.`Add order performance.` When hashes collide, a linear search must be done to locate a key in the dictionary. If we add a key earlier, it is faster to locate. `Dictionary Order `dictionary-order-python`String key performance.` In another test, I compared string keys. I found that long string keys take longer to look up than short ones. Shorter keys are faster. `Dictionary String Key `dictionary-string-key-python`Counter.` For frequencies, we can use a special Counter from the collections module. This can make counters easier to add in programs. `Counter `counter-python`A summary.` A dictionary is usually implemented as a hash table. Here a special hashing algorithm translates a key (often a string) into an integer.`For a speedup,` this integer is used to locate the data. This reduces search time. For programs with performance trouble, using a dictionary is often the initial path to optimization.

?@B plants@{}B # Add three key-@ tuples@the d@. Bplants[B"radish"B]@2 plants[B"squash"B]@4 plants[B"carrot"B]@7B # @syntax 1. B@(plants[B"radish"B])B # @syntax 2. B@(plants.BgetB(B"tuna"B)) @(plants.BgetB(B"tuna"B, "no tuna found")) B 2 None no tuna foundB lookup@{"cat": 1, "dog": 2}B # The d@ has no fish key! B@(lookup[B"fish"B]) B Traceback (most recent call last): File "C:\programs\file.py", line 5,@<module> ?@(lookup["fish"]) BKeyErrorB: 'fish'B animals@{} animals["monkey"]@1 animals["tuna"]@2 animals["giraffe"]@4B # Use in. Bif B"tuna"B BinB animals: ?@("Has tuna") else: ?@("No tuna")B # Use@on nonexistent key. Bif B"elephant"B BinB animals: ?@("Has elephant") else: ?@("No elephant") B Has tuna No elephantB animals@{B"parrot"B: 2, B"fish"B: 6}B # Use len built-in on animals. B@("L@:", BlenB(animals)) B L@: 2B hits@{B"home"B: 125, B"sitemap"B: 27, B"about"B: 43} keys@hits.BkeysB() @s@hits.B@sB() @(B"Keys:"B) @(keys) @(len(keys)) @(B"@s:"B) @(@s) @(len(@s)) B Keys: dict_keys(['home', 'about', 'sitemap']) 3 @s: dict_@s([125, 43, 27]) 3B B# Same as previous program. Bhits@{B"home"B: 124, B"sitemap"B: 26, B"about"B: 32}B # Sort the keys from the d@. Bkeys@BsortedB(hits.keys()) @(keys) B ['about', 'home', 'sitemap']B rents@{B"apartment"B: 1000, B"house"B: 1300}B # C@@@ of tuples. BrentItems@rents.BitemsB()B # @and display tuple items. B@rentItem@rentItems: ?@("Place:", rentItem[0]) ?@("Cost:", rentItem[1]) ?@("") B Place: house Cost: 1300 Place: apartment Cost: 1000BPython error:B TypeError: 'tuple' object does not support item assignmentB B# C@ a d@. Bdata@{B"a"B: 1, B"b"B: 2, B"c"B: 3}B # @over items@unpack each item. B@k, v@data.BitemsB():B ?# @ key@@. ?B@(k, v) B a 1 c 3 b 2B plants@{B"radish"B: 2, B"squash"B: 4, B"carrot"B: 7}B # @over d@ directly. # @This only accesses keys. B@B plant@plants: ?@(plant) B radish carrot squashB systems@{B"mac"B: 1, B"windows"B: 5, B"linux"B: 1}B # Remove key-@ at "windows" key. BdelB systems[B"windows"B]B # @ d@. B@(systems) B {'mac': 1, 'linux': 1}B B# First d@. Bpets1@{B"cat"B: "feline", B"dog"B: "canine"}B # Second d@. Bpets2@{B"dog"B: "animal", B"parakeet"B: "bird"}B # Update first d@ with second. Bpets1.BupdateB(pets2)B # @ both dictionaries. B@(pets1) @(pets2) B {'parakeet': 'bird', 'dog': 'animal', 'cat': 'feline'} {'dog': 'animal', 'parakeet': 'bird'}B original@{B"box"B: 1, B"cat"B: 2, B"apple"B: 5}B # C@ copy of d@. Bmodified@original.BcopyB()B # Change copy only. Bmodified["cat"]@200 modified["apple"]@9B # Original is still the same. B@(original) @(modified) B {'box': 1, 'apple': 5, 'cat': 2} {'box': 1, 'apple': 9, 'cat': 200}B B# A @ of keys. Bkeys@[B"bird"B, B"plant"B, B"fish"B]B # C@ d@ from keys. Bd@Bdict.fromkeysB(keys, 5)B # @. B@(d) B {'plant': 5, 'bird': 5, 'fish': 5}B B# C@ @ of tuple pairs. # @These are key-@ pairs. Bpairs@[("cat", "meow"), ("dog", "bark"), ("bird", "chirp")]B # C@ @@d@. Blookup@BdictB(pairs)B # Test the d@. B@(lookup.get(B"dog"B)) @(len(lookup)) B bark 3B @timeB # Input d@. Bsystems@{B"mac"B: 1, B"windows"B: 5, B"linux"B: 1} @(time.time())B # Version 1: use get. Bv@0 x@0 B@B i@range(10000000): ?x@systems.get(B"windows"B, -1) ?if x != -1: ??v@x @(time.time())B # Version 2: use in. Bv@0 B@B i@range(10000000): ?if B"windows"B@systems: ??v@systems[B"windows"B] @(time.time()) BResultsB 1478552825.0586164 1478552827.0295532 (get@B1.97 sB) 1478552828.1397061 (in @B1.11 sB)B @time data@{B"parrot"B: 1, B"frog"B: 1, B"elephant"B: 2, B"snake"B: 5} items@data.BitemsB() @(time.time())B # Version 1: get. B@B i@range(10000000): ?v@0 ?@key@data: ??v@data[key] @(time.time())B # Version 2: items. B@B i@range(10000000): ?v@0 ?@tuple@items: ??v@tuple[1] @(time.time()) BResultsB 1478467043.8872652 1478467048.6821966 (version 1@B4.79 sB) 1478467053.2630682 (version 2@B4.58 sB)B B# The first three letters are repeated. Bletters@B"abcabcdefghi"B frequencies@{} @c@letters:B ?# If no key exists, get @s the @ 0. ?# @We then add one@increase the frequency. ?# @So we start at 1@progress@2@then 3. ?Bfrequencies[c]@frequencies.BgetB(c, B0B)@1 @f@frequencies.items():B ?# Pr@the tuple pair. ?B@(f) B ('a', 2) ('c', 2) ('b', 2) ('e', 1) ('d', 1) ('g', 1) ('f', 1) ('i', 1) ('h', 1)B reptiles@{B"frog"B: 20, B"snake"B: 8} inverted@{}B # Use items loop. # @Turn each @ @o a key. B@key, @@reptiles.BitemsB(): ?inverted[@]@key ? @(B":::ORIGINAL:::"B) @(reptiles) @(B":::KEYS, VALUES SWAPPED:::"B) @(inverted) B :::ORIGINAL::: {'frog': 20, 'snake': 8} :::KEYS, VALUES SWAPPED::: {8: B'snake'B, 20: B'frog'B}B

2+/RaT8\-5SVTX].094gets valuescauses KeyErrorinlen on dictionarykeyssorts keys in dictionaryitems methodunpacks itemsloops over dictionarydelupdatecopyfromkeysdict built-inbenchmarks getbenchmarks loopscounts letter frequenciesinverts a dictionary