{"id":2501,"date":"2025-09-26T10:48:35","date_gmt":"2025-09-26T02:48:35","guid":{"rendered":"http:\/\/blue.yn.cn\/?p=2501"},"modified":"2025-12-11T14:40:09","modified_gmt":"2025-12-11T06:40:09","slug":"dictionaries","status":"publish","type":"post","link":"http:\/\/blue.yn.cn\/?p=2501","title":{"rendered":"9. Dictionaries"},"content":{"rendered":"<p>A dictionary is like a list, but more general. In a list, the index positions have to be integers; in a dictionary, the indices can be (almost) any type.<\/p>\n<p>You can think of a dictionary as a mapping between a set of indices (which are called keys) and a set of values. Each key maps to a value. The association of a key and a value is called a key-value pair or sometimes an item.<\/p>\n<p>As an example, we'll build a dictionary that maps from English to Spanish words, so the keys and the values are all strings.<\/p>\n<p>The function <code>dict<\/code> creates a new dictionary with no items. Because <code>dict<\/code> is the name of a built-in function, you should avoid using it as a variable name.<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; eng2sp = dict()\n>&gt;&gt; print(eng2sp)\n{}<\/code><\/pre>\n<p>The curly brackets, <code>{}<\/code>, represent an empty dictionary. To add items to the dictionary, you can use square brackets:<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; eng2sp[&#039;one&#039;] = &#039;uno&#039;<\/code><\/pre>\n<p>This line creates an item that maps from the key <code>&#039;one&#039;<\/code> to the value &quot;uno&quot;. If we print the dictionary again, we see a key-value pair with a colon between the key and value:<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; print(eng2sp)\n{&#039;one&#039;: &#039;uno&#039;}<\/code><\/pre>\n<p>This output format is also an input format. For example, you can create a new dictionary with three items.<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; eng2sp = {&#039;one&#039;: &#039;uno&#039;, &#039;two&#039;: &#039;dos&#039;, &#039;three&#039;: &#039;tres&#039;}\n>&gt;&gt; print(eng2sp)\n{&#039;one&#039;: &#039;uno&#039;, &#039;two&#039;: &#039;dos&#039;, &#039;three&#039;: &#039;tres&#039;}<\/code><\/pre>\n<p>Since Python 3.7x the order of key-value pairs is the same as their input order, i.e. dictionarys are now orderd structures.<\/p>\n<p>But that doesn't really matter because the elements of a dictionary are never indexed with integer indices. Instead, you use the keys to look up the corresponding values:<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; print(eng2sp[&#039;two&#039;])\n&#039;dos&#039;<\/code><\/pre>\n<p>The key <code>&#039;two&#039;<\/code> always maps to the value &quot;dos&quot; so the order of the items doesn't matter.<\/p>\n<p>If the key isn't in the dictionary, you get an exception:<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; print(eng2sp[&#039;four&#039;])\nKeyError: &#039;four&#039;<\/code><\/pre>\n<p>The <code>len<\/code> function works on dictionaries; it returns the number of key-value pairs:<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; len(eng2sp)\n3<\/code><\/pre>\n<p>The <code>in<\/code> operator works on dictionary; it tells you whether something appears as a key in the dictionary (appearing as a value is not good enough)<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; &#039;one&#039; in eng2sp\nTrue\n>&gt;&gt; &#039;uno&#039; in eng2sp\nFalse<\/code><\/pre>\n<p>To see whether something appears as a value in a dictionary, you can use the method <code>values<\/code>, which returns the values as a type that can be converted to a list, and then use the <code>in<\/code> operator:<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; vals = list(eng2sp.values())\n>&gt;&gt; &#039;uno&#039; in vals\nTrue<\/code><\/pre>\n<p>The <code>in<\/code> operator uses different algorithms for lists and dictionaries. For lists, it uses a linear search algorithm. As the list gets longer, the search tiem gets longer in direct proportion to the length of the list. For dictionaries, Python uses an algorithm called hash table that has a remarkable property: the <code>in<\/code> operator takes about the same amount of time to no matter how many items there are in a dictionary. I won't explain why hash functions are so magical, but you cna read more about it at <a href=\"https:\/\/wikipedia.org\/wiki\/Hash_table\">https:\/\/wikipedia.org\/wiki\/Hash_table<\/a>.<\/p>\n<p><strong>Exercise 1:<\/strong> Download a copy of the file<\/p>\n<p><a href=\"https:\/\/www.py4e.com\/code3\/words.txt\">https:\/\/www.py4e.com\/code3\/words.txt<\/a><\/p>\n<p>Write a program that reads the word in words.txt and store them as keys in a dictionary. It doesn't matter what the values are. Then you can use the <code>in<\/code> operator as a fast way to check whether a string is in the dictionary.<\/p>\n<pre><code class=\"language-python\">fhand = open(&#039;words.txt&#039;, encoding=&#039;utf-8&#039;)\ndic = dict()\nfor line in fhand:\n    words = line.split()\n    for word in words:\n        dic[word] = 1\nletter = &#039;laptops&#039;\nif letter in dic:\n    print(letter, &#039;is in the dictionary&#039;)<\/code><\/pre>\n<h3>Dictionary as a set of counters<\/h3>\n<p>Suppose you are given a string and you want to count how many times each letter appears. There are several ways you could do it:<\/p>\n<ol>\n<li>\n<p>You could create 26 variables, one for each letters of the alphabet. The you could traverse the string and, for each character, increment the corresponding counter, probably using a chained conditional.<\/p>\n<\/li>\n<li>\n<p>You could create a list with 26 elements. Then you could convert each character to number (using the build-in function <code>ord<\/code>), use the number as an index into the list, and increment the appropriate counter.<\/p>\n<\/li>\n<li>\n<p>You could create a dictionary with character as keys and counters as the corresponding values. The first time you see a character, you would add an item to the dictionary. After that you would increment the value of an existing item.<\/p>\n<\/li>\n<\/ol>\n<p>Each of these options performs the same computation; but each of them implements that computation in a different way.<\/p>\n<p>An implementation is a away of performing a computation; some implementations are better than others. For example, an advantage of the dictionary implementation is that we don't have to know ahead of time which letters appear in the string and we only have to make room for the letters that do appear.<\/p>\n<p>Here is what the code might look like:<\/p>\n<pre><code class=\"language-python\">word = &#039;brontosaurus&#039;\nd = dict()\nfor c in word:\n    if c not in d:\n        d[c] = 1\n    else:\n        d[c] = d[c] + 1\nprint(d)<\/code><\/pre>\n<p>We are effectively computing a histogram, Which is a statistical term for a set of counters(or frequencies).<\/p>\n<p>The <code>for<\/code> loop traverses the string. Each time through the loop, if the character <code>c<\/code> is not in the dictionary, we create a new item with the key <code>c<\/code> and the initial value 1 (since we have seen this letter once). If <code>c<\/code> is already in the dictionary we increment <code>d[&#039;c&#039;]<\/code>.<\/p>\n<p>Here's the output of the program:<\/p>\n<pre><code class=\"language-python\">{&#039;b&#039;: 1, &#039;r&#039;: 2, &#039;o&#039;: 2, &#039;n&#039;: 1, &#039;t&#039;: 1, &#039;s&#039;: 2, &#039;a&#039;: 1, &#039;u&#039;: 2}<\/code><\/pre>\n<p>The histogram indicates that the letters &quot;a&quot; and &quot;b&quot; appear once; &quot;o&quot; appears twice, and so on.<\/p>\n<p>Dictionary has a method called <code>get<\/code> that takes a key and a default value. If the key appears in the dictionary, <code>get<\/code> returns the corresponding value; otherwise it returns the default value. For example:<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; counts = { &#039;chuck&#039; : 1 , &#039;annie&#039; : 42, &#039;jan&#039;: 100}\n>&gt;&gt; print(counts.get(&#039;jan&#039;, 0))\n100\n>&gt;&gt; print(counts.get(&#039;tim&#039;, 0))\n0<\/code><\/pre>\n<p>We can use <code>get<\/code> to write our histogram loop more concisely. Because the <code>get<\/code> method automatically handles the case where a key is not in a dictionary, we can reduce four lines down to one and eliminate the <code>if<\/code> statement.<\/p>\n<pre><code class=\"language-python\">word = &#039;brontosaurus&#039;\nd = dict()\nfor c in word:\n    d[c] = d.get(c,0) + 1\nprint(d)<\/code><\/pre>\n<p>The use of the <code>get<\/code> method to simplify this counting loop ends up being a very commonly used &quot;idiom&quot; in Pythond and we will use it many times in the rest of the book. So you should take a moment and compare the loop using the <code>if<\/code> statement and <code>in<\/code> operator with the loop using the <code>get<\/code> method. They do exactly the same thing, but one is more succinct.<\/p>\n<h3>Dictionaries and files<\/h3>\n<p>Once of the common uses of a dictionary is to count the occurence of words in a file with some written text. Let's start with a very simple file of words taken from the text of Romeo and Juliet.<\/p>\n<p>For the first set of examples, we will use a shortened and simplified version of the text with no punctuation. Later we will work with the text of the scene with punctuation inclued.<\/p>\n<pre><code class=\"language-python\">But soft what light through yonder window breaks\nIt is the east and Juliet is the sun\nArise fair sun and kill the envious moon\nWho is already sick and pale with grief<\/code><\/pre>\n<p>We will write a Python program to read through the lines of the file, break each line into a list of words, and thehn loop through each of the words in the line and count each word using a dictionary.<\/p>\n<p>You will see that we have two <code>for<\/code> loops. The outer loop is reading the lines of the file and inner loop is iterating through each of the words on that particular line. This is an example of a pattern called nested loops because one of the loops is the outer loop and the other loop is the inner loop.<\/p>\n<p>Because the inner loop executes all of its iterations each time the outer loop makes a single iteration, we think of the inner loop as iterating &quot;more quickly&quot; and the outer loop as iterating more slowly.<\/p>\n<p>The combination of the two nested loops ensures that we will count every word on every line of the iput file.<\/p>\n<pre><code class=\"language-python\">\nfname = input(&#039;Enter the file name: &#039;)\ntry:\n    fhand = open(fname)\nexcept:\n    print(&#039;File cannot be opened:&#039;, fname)\n    exit()\n\ncounts = dict()\nfor line in fhand:\n    words = line.split()\n    for word in words:\n        if word not in counts:\n            counts[word] = 1\n        else:\n            counts[word] += 1\n\nprint(counts)<\/code><\/pre>\n<p>In our <code>else<\/code> statement, we use the more compact alternative for incrementing a variable. <code>counts[word] += 1<\/code> is equivalent to <code>counts[word] = counts[word] + 1<\/code>. Either method can be used to change the value of a variable by any desired amount. Similar alternative exist for <code>-=<\/code>, <code>*=<\/code>, and <code>\/=<\/code>.<\/p>\n<p>When we run the program, we see a raw dump of all of the counts in unsorted hash order. (the romeo.txt file is available at <a href=\"https:\/\/www.py4e.com\/code3\/romeo.txt\">https:\/\/www.py4e.com\/code3\/romeo.txt<\/a>)<\/p>\n<pre><code class=\"language-python\">python count1.py\nEnter the file name: romeo.txt\n{&#039;But&#039;: 1, &#039;soft&#039;: 1, &#039;what&#039;: 1, &#039;light&#039;: 1, &#039;through&#039;: 1, &#039;yonder&#039;: 1,\n&#039;window&#039;: 1, &#039;breaks&#039;: 1, &#039;It&#039;: 1, &#039;is&#039;: 3, &#039;the&#039;: 3, &#039;east&#039;: 1, &#039;and&#039;: 3,\n&#039;Juliet&#039;: 1, &#039;sun&#039;: 2, &#039;Arise&#039;: 1, &#039;fair&#039;: 1, &#039;kill&#039;: 1, &#039;envious&#039;: 1,\n&#039;moon&#039;: 1, &#039;Who&#039;: 1, &#039;already&#039;: 1, &#039;sick&#039;: 1, &#039;pale&#039;: 1, &#039;with&#039;: 1,\n&#039;grief&#039;: 1}<\/code><\/pre>\n<p>It is a bit inconvenient to look through the dictionary to find the most common words and their counts, so we need to add some more Python code to get us output that will be more helpful.<\/p>\n<h3>Looping and dictionaries<\/h3>\n<p>If you use a dictionary as the sequence in a <code>for<\/code> statement, it traverses the keys of the dictionary. This loop prints each key and the corresponding value:<\/p>\n<pre><code class=\"language-python\">counts = { &#039;chuck&#039; : 1 , &#039;annie&#039; : 42, &#039;jan&#039;: 100}\nfor key in counts:\n    print(key, counts[key])<\/code><\/pre>\n<p>Here's what the output looks like:<\/p>\n<pre><code class=\"language-python\">chuck 1\nannie 42\njan 100<\/code><\/pre>\n<p>Again, the keys are ordered.<\/p>\n<p>We can use this pattern to implement the various loop idioms that we have described earlier. For example if we wanted to find all the entries in a dictionary with a value above ten, we could write the following code:<\/p>\n<p>The <code>for<\/code> loop iterates through the keys of the dictionary, so we must use the index operator to retrieve the correspongding value for each key. Here's what the output looks like:<\/p>\n<pre><code class=\"language-python\">annie 42\njan 100<\/code><\/pre>\n<p>We see only the entries with a value above 10.<\/p>\n<p>If you want to print the keys in alphabetical order, you first make a list of the keys in the dictionary using the <code>keys<\/code> method available in dictionary objects, and then sort that list and loop through the sorted list, looking up each key and printing out key-value pairs in storted order as follows:<\/p>\n<pre><code class=\"language-python\">counts = { &#039;chuck&#039; : 1 , &#039;annie&#039; : 42, &#039;jan&#039;: 100}\nlst = list(counts.keys())\nprint(lst)\nlst.sort()\nprint(lst)\nfor key in lst:\n    print(key, counts[key])<\/code><\/pre>\n<p>Here's what the output looks like:<\/p>\n<pre><code class=\"language-python\">[&#039;chuck&#039;, &#039;annie&#039;, &#039;jan&#039;]\n[&#039;annie&#039;, &#039;chuck&#039;, &#039;jan&#039;]\nannie 42\nchuck 1\njan 100<\/code><\/pre>\n<p>First you see the list of keys in non-alphabetical order that we get from the <code>keys<\/code> method. Then we see the key-value pairs in alphabetical order from the <code>for<\/code> loop.<\/p>\n<h3>Advanced text parsing<\/h3>\n<p>In the above example using the file romeo.txt, we made the file as simple as possible by removing all punctuation by hand. The actual text has lots of punctuation, as shown below.<\/p>\n<pre><code class=\"language-python\">But, soft! what light through yonder window breaks?\nIt is the east, and Juliet is the sun.\nArise, fair sun, and kill the envious moon,\nWho is already sick and pale with grief,<\/code><\/pre>\n<p>Since the Python <code>split<\/code> function looks for spaces and treats words as tokens separated by spaces, we would treat the word &quot;soft!&quot; and &quot;soft&quot; as different words and create a separate dictionary entry for each word.<\/p>\n<p>Also since the file has capitalization, we would treat &quot;Who&quot; and &quot;who&quot; as different words with different counts.<\/p>\n<p>We can solve both these problems by using the string methods <code>lower<\/code>, <code>punctuation<\/code>, and <code>translate<\/code>. The <code>translate<\/code> is the most subtle of the methods. Here is the documentation for <code>translate<\/code>:<\/p>\n<p><code>line.translate(str.maketrans(fromstr, tostr, deletestr))<\/code><\/p>\n<p>Replace the character in <code>fromstr<\/code> with the character in the same position in <code>tostr<\/code> and delete all character that are in <code>deletestr<\/code>. The <code>fromstr<\/code> and <code>tostr<\/code> can be empty strings and the <code>deletestr<\/code> parameter can be ommitted.<\/p>\n<p>We will not specify the <code>tostr<\/code> but we will use the <code>deletestr<\/code> parameter to delete all of the punctuation. We will even let Python tell us the list of character that it considers &quot;punctuation&quot;:<\/p>\n<pre><code class=\"language-python\">>&gt;&gt; import string\n>&gt;&gt; string.punctuation\n&#039;!&quot;#$%&amp;\\&#039;()*+,-.\/:;&lt;=&gt;?@[\\\\]^_`{|}~&#039;<\/code><\/pre>\n<p>The parameters used by <code>translate<\/code> were different in Python 2.0.<\/p>\n<p>We make the following modifications to our program:<\/p>\n<pre><code class=\"language-python\">import string\n\nfname = input(&#039;Enter the file name: &#039;)\ntry:\n    fhand = open(fname)\nexcept:\n    print(&#039;File cannot be opened:&#039;, fname)\n    exit()\n\ncounts = dict()\nfor line in fhand:\n    line = line.rstrip()\n    # First two parameters are empty strings\n    line = line.translate(line.maketrans(&quot;&quot;, &quot;&quot;, string.punctuation))\n    line = line.lower()\n    words = line.split()\n    for word in words:\n        if word not in counts:\n            counts[word] = 1\n        else:\n            counts[word] += 1\n\nprint(counts)<\/code><\/pre>\n<p>Part of learning the &quot;Art of Python&quot; or &quot;Thinking Pythonically&quot; is realizing that Python often has built-in capabilities for many common data analysis problems. Over time, you will see enough code and read enough of the documentation to know where to look to see if someone has already written something that makes your job much easier.<\/p>\n<p>The following is an abbreviated version of the output:<\/p>\n<pre><code class=\"language-python\">Enter the file name: romeo-full.txt\n{&#039;romeo&#039;: 40, &#039;and&#039;: 42, &#039;juliet&#039;: 32, &#039;act&#039;: 1, &#039;2&#039;: 2, &#039;scene&#039;: 2,\n&#039;ii&#039;: 1, &#039;capulets&#039;: 1, &#039;orchard&#039;: 2, &#039;enter&#039;: 1, &#039;he&#039;: 5, &#039;jests&#039;: 1,\n&#039;at&#039;: 9, &#039;scars&#039;: 1, &#039;that&#039;: 30, &#039;never&#039;: 2, &#039;felt&#039;: 1, &#039;a&#039;: 24,\n&#039;wound&#039;: 1, &#039;appears&#039;: 1, &#039;above&#039;: 6, &#039;window&#039;: 2, &#039;but&#039;: 18,\n&#039;soft&#039;: 1, &#039;what&#039;: 11, &#039;light&#039;: 5, &#039;through&#039;: 2, &#039;yonder&#039;: 2,\n&#039;breaks&#039;: 1, ...}<\/code><\/pre>\n<p>Looking through this output is still unwieldy and we can use Python to give us exactly what we are looking for, but to do so, we need to learn about Python tuples. We will pick up this example once we learn about tuples.<\/p>\n<h3>Debugging<\/h3>\n<p>As you work with bigger datasets it can become unwieldy to debug by printing and checking data by hand. Here are some suggestions for debugging large datasets.<\/p>\n<p><strong>Scale down the input<\/strong><br \/>\nIf possible, reduce the size of the dataset. For example if the program reads a text file, start with just the first 10 lines, or with the smallest example you can find. You can either edit the files themselves, or (better) modify the program so it reads only the first <code>n<\/code> lines.<\/p>\n<p>If there is an error, you can reduce <code>n<\/code> to the smallest value that manifests the error, and then increase it gradually as you find and correct errors.<\/p>\n<p><strong>Check summaries and types<\/strong><br \/>\nInstead of printing and checking the entire dataset, consider printing summaries of the data: for example, the number of items in a dictionary or the total of a list of numbers.<\/p>\n<p>A common cause of runtime errors is a value that is not the right type. For debugging this kind of error, it is often enough to print the type of a value.<\/p>\n<p><strong>Write self-checks<\/strong><br \/>\nSometimes you can write code to check for errors automatically. For example, if you are computing the average of numbers, you could check that the results is not greater than the largest element in the list or less than the smallest. This is called a &quot;sanity check&quot; because it detects results that are &quot;completely illogical&quot;.<\/p>\n<p>Another kind of check compares the results of two different computations to see if they are consistent. This is called a &quot;consistency check&quot;.<\/p>\n<p><strong>Pretty print the output<\/strong><br \/>\nFormatting debugging output can make it easier to spot an error.<\/p>\n<p>Again, time you spend building scaffolding can reduce the time you spend debugging.<\/p>\n<h3>Glossary<\/h3>\n<p><strong>dictionary<\/strong><br \/>\nA mapping from a set of keys to their corresponding values.<\/p>\n<p><strong>hashtable<\/strong><br \/>\nA function used by a hashtable to compute the location for a key.<\/p>\n<p><strong>histogram<\/strong><br \/>\nA set of counters.<\/p>\n<p><strong>implementation<\/strong><br \/>\nA way of performing a computation.<\/p>\n<p><strong>item<\/strong><br \/>\nAnother name for a key-value pair.<\/p>\n<p><strong>key<\/strong><br \/>\nAn object that appears in a dictionary as the first part of a key-value pair.<\/p>\n<p><strong>key-value pair<\/strong><br \/>\nThe representation of the mapping from a key to a value.<\/p>\n<p><strong>lookup<\/strong><br \/>\nA dictionary operation that takes a key and fins the corresponding value.<\/p>\n<p><strong>nested loops<\/strong><br \/>\nWhen there are one or more loops &quot;inside&quot; of another loop. The inner loop runs to completion each time the outer loop runs once.<\/p>\n<p><strong>value<\/strong><br \/>\nAn object that appears in a dictionary as the second part of a key-value pair. This is more specific than our previous use of the word &quot;value&quot;.<\/p>\n<h3>Exercises<\/h3>\n<p><strong>Exercise 2:<\/strong> Write a program that categorizes each mail message by which day of the week the commit was done. To do this look for lines that start with &quot;From&quot;, then look for the third word and keep a running count of each of the days of the week. At the end of the program print out the contents of your dictionary (order does not matter).<\/p>\n<p>Sample Line:<\/p>\n<pre><code class=\"language-python\">From stephen.marquard@uct.ac.za Sat Jan  5 09:14:16 2008<\/code><\/pre>\n<p>Sample Execution:<\/p>\n<pre><code class=\"language-python\">Enter a file name: mbox-short.txt\n{&#039;Fri&#039;: 20, &#039;Thu&#039;: 6, &#039;Sat&#039;: 1}<\/code><\/pre>\n<pre><code class=\"language-python\">fname = input(&#039;Enter the file name: &#039;)\ntry:\n    fhand = open(fname)\nexcept:\n    print(&#039;File cannot be opened:&#039;, fname)\n    exit()\ndow = dict()\nfor line in fhand:\n    if not line.startswith(&#039;From &#039;): continue\n    words = line.split()\n    if len(words) &lt; 3: continue\n    if words[2] not in dow:\n        dow[words[2]] = 1\n    else:\n        dow[words[2]] += 1\nprint(dow)<\/code><\/pre>\n<p><strong>Exercise 3:<\/strong> Write a program to read through a mail log, build a histogram using a dictionary to count how many messages have come from each mail address, and print the dictionary.<\/p>\n<pre><code class=\"language-python\">fname = input(&#039;Enter the file name: &#039;)\ntry:\n    fhand = open(fname)\nexcept:\n    print(&#039;File cannot be opened:&#039;, fname)\n    exit()\nmailadd = dict()\nfor line in fhand:\n    if not line.startswith(&#039;From &#039;): continue\n    words = line.split()\n    if len(words) &lt; 3: continue\n    if words[1] not in mailadd:\n        mailadd[words[1]] = 1\n    else:\n        mailadd[words[1]] += 1\nprint(mailadd)<\/code><\/pre>\n<pre><code class=\"language-python\">Enter file name: mbox-short.txt\n{&#039;gopal.ramasammycook@gmail.com&#039;: 1, &#039;louis@media.berkeley.edu&#039;: 3,\n&#039;cwen@iupui.edu&#039;: 5, &#039;antranig@caret.cam.ac.uk&#039;: 1,\n&#039;rjlowe@iupui.edu&#039;: 2, &#039;gsilver@umich.edu&#039;: 3,\n&#039;david.horwitz@uct.ac.za&#039;: 4, &#039;wagnermr@iupui.edu&#039;: 1,\n&#039;zqian@umich.edu&#039;: 4, &#039;stephen.marquard@uct.ac.za&#039;: 2,\n&#039;ray@media.berkeley.edu&#039;: 1}<\/code><\/pre>\n<p><strong>Exercise 4:<\/strong> Add code to the above program to figure out who has the most messages in the file. After all the data has been read and the dictionary has been created, look through the dictionary using a maximum loop (see Chapter 5: Maximum and minimum loops) to find who has the most messages and print how many messages the person has.<\/p>\n<pre><code class=\"language-python\">Enter a file name: mbox-short.txt\ncwen@iupui.edu 5\n\nEnter a file name: mbox.txt\nzqian@umich.edu 195<\/code><\/pre>\n<pre><code class=\"language-python\">fname = input(&#039;Enter the file name: &#039;)\ntry:\n    fhand = open(fname)\nexcept:\n    print(&#039;File cannot be opened:&#039;, fname)\n    exit()\nmailadd = dict()\nfor line in fhand:\n    if not line.startswith(&#039;From &#039;): continue\n    words = line.split()\n    if len(words) &lt; 3: continue\n    if words[1] not in mailadd:\n        mailadd[words[1]] = 1\n    else:\n        mailadd[words[1]] += 1\nmaximum = 0\nfor key in mailadd:\n    maximum = max(maximum, mailadd[key])\nfor key in mailadd:\n    if mailadd[key] == maximum: print(key, mailadd[key])<\/code><\/pre>\n<pre><code class=\"language-python\">lst = list()\nfor key, val in mailadd.items():\n    lst.append((val, key))\nlst.sort(reverse=True)\nfor key, val in lst[:1]:\n    print(key, val)<\/code><\/pre>\n<p><strong>Exercise 5:<\/strong> This program records the domain name (instead of the address) where the message was sent from instead of who the mail came from (i.e., the whole email address). At the end of the program, print out the contents of your dictionary.<\/p>\n<pre><code class=\"language-python\">Enter a file name: mbox-short.txt\n{&#039;media.berkeley.edu&#039;: 4, &#039;uct.ac.za&#039;: 6, &#039;umich.edu&#039;: 7,\n&#039;gmail.com&#039;: 1, &#039;caret.cam.ac.uk&#039;: 1, &#039;iupui.edu&#039;: 8}<\/code><\/pre>\n<pre><code class=\"language-python\">fname = input(&#039;Enter the file name: &#039;)\ntry:\n    fhand = open(fname)\nexcept:\n    print(&#039;File cannot be opened:&#039;, fname)\n    exit()\ndomain = dict()\nfor line in fhand:\n    if not line.startswith(&#039;From &#039;): continue\n    words = line.split()\n    if len(words) &lt; 3: continue\n    word = words[1]\n    word = word.split(&#039;@&#039;)\n    if word[1] not in domain:\n        domain[word[1]] = 1\n    else:\n        domain[word[1]] += 1\nprint(domain)<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>A dictionary is like a list, but more general. In a lis&#8230; &raquo; <a class=\"read-more-link\" href=\"http:\/\/blue.yn.cn\/?p=2501\">\u9605\u8bfb\u5168\u6587<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[24],"tags":[],"class_list":["post-2501","post","type-post","status-publish","format-standard","hentry","category-python"],"_links":{"self":[{"href":"http:\/\/blue.yn.cn\/index.php?rest_route=\/wp\/v2\/posts\/2501","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/blue.yn.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blue.yn.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blue.yn.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/blue.yn.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2501"}],"version-history":[{"count":8,"href":"http:\/\/blue.yn.cn\/index.php?rest_route=\/wp\/v2\/posts\/2501\/revisions"}],"predecessor-version":[{"id":2629,"href":"http:\/\/blue.yn.cn\/index.php?rest_route=\/wp\/v2\/posts\/2501\/revisions\/2629"}],"wp:attachment":[{"href":"http:\/\/blue.yn.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2501"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blue.yn.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2501"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blue.yn.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2501"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}