 \chapter{Dictionaries}
\label{lec-dictionaries}

All of the compound data types we have studied in detail so
far---strings, lists, and tuples---are sequence types, which use
integers as indices to access the multiple values they contain.
\myidx{Dictionaries} are a different kind of compound type. They are
Python's \myidx{mapping type}. They map \myidx{keys} which can be
of any immutable type to values which can be of any type, just like
the values of a list or tuple.

As an example, we will create a dictionary to translate English words
into Spanish. For this dictionary, the keys are strings.
One way to create a dictionary is to start with the empty dictionary
and add \myidx{key-value pairs} . The empty dictionary is denoted
\{\}:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> eng2sp = {}
>>> eng2sp['one'] = 'uno'
>>> eng2sp['two'] = 'dos'
\end{pythonInteractive}
\end{minipage}
The first assignment creates a dictionary named \pythoninline{eng2sp};
the other assignments add new key-value pairs to the dictionary. We
can print the current value of the dictionary in the usual way: 

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> print eng2sp
{'two': 'dos', 'one': 'uno'}
\end{pythonInteractive}
\end{minipage}
The key-value pairs of the dictionary are separated by commas. Each
pair contains a key and a value separated by a colon.
The order of the pairs may not be what you expected. Python uses
complex algorithms to determine where the key-value pairs are stored
in a dictionary. For our purposes we can think of this ordering as
unpredictable.

Another way to create a dictionary is to provide a list of key-value
pairs using the same syntax as the previous output:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> eng2sp = {'one': 'uno', 'two': 'dos', 'three': 'tres'}
\end{pythonInteractive}
\end{minipage}
It doesn't matter what order we write the pairs. The values in a
dictionary are accessed with keys, not with indices, so there is no
need to care about ordering.
Here is how we use a key to look up the corresponding value:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> print eng2sp['two']
'dos'
\end{pythonInteractive}
\end{minipage}
The key \pythoninline{'two'} yields the value \pythoninline{'dos'}.

\section{Dictionary operations}
The \pythoninline{del} statement removes a key-value pair from a
dictionary. For example, the following dictionary contains the names
of various fruits and the number of each fruit in stock: 

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> inventory = {'apples': 430, 'bananas': 312, 'oranges': 525, 'pears': 217}
>>> print inventory
{'oranges': 525, 'apples': 430, 'pears': 217, 'bananas': 312}
\end{pythonInteractive}
\end{minipage}
If someone buys all of the pears, we can remove the entry from the
dictionary:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> del inventory['pears']
>>> print inventory
{'oranges': 525, 'apples': 430, 'bananas': 312}
\end{pythonInteractive}
\end{minipage}
Or if we're expecting more pears soon, we might just change the value
associated with pears:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> inventory['pears'] = 0
>>> print inventory
{'oranges': 525, 'apples': 430, 'pears': 0, 'bananas': 312}
\end{pythonInteractive}
\end{minipage}

The \pythoninline{len} function also works on dictionaries; it returns
the number of key-value pairs: 

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> len(inventory)
4
\end{pythonInteractive}
\end{minipage}

\section{Dictionary methods}
Dictionaries have a number of useful built-in methods
The \pythoninline{keys} method takes a dictionary and returns a list of the keys
that appear, but instead of the function syntax
\pythoninline{keys(eng2sp)}, we use
the method syntax \pythoninline{eng2sp.keys()}.

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> eng2sp.keys()
['one', 'three', 'two']
\end{pythonInteractive}
\end{minipage}

This form of dot notation specifies the name of the method,
\pythoninline{keys}, and the name of the object on which to apply the
method, \pythoninline{eng2sp}. The parentheses indicate that this
method takes no parameters. 
A method call is called an \myidx{invocation}; in this case, we
would say that we are invoking the keys method on the object
\pythoninline{eng2sp}. 

The \pythoninline{values} method is similar; it returns a list of the
values in the dictionary:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> eng2sp.values()
['uno', 'tres', 'dos']
\end{pythonInteractive}
\end{minipage}
The items method returns both, in the form of a list of tuples---one
for each key-value pair:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> eng2sp.items()
[('one','uno'), ('three', 'tres'), ('two', 'dos')]
\end{pythonInteractive}
\end{minipage}
The syntax provides useful type information. The square brackets
indicate that this is a list. The parentheses indicate that the
elements of the list are tuples.

If a method takes an argument, it uses the same syntax as a function
call. For example, the method \pythoninline{has\_key} takes a key and
returns true if the key appears in the dictionary:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> eng2sp.has_key('one')
True
>>> eng2sp.has_key('deux')
False
\end{pythonInteractive}
\end{minipage}
If you try to call a method without specifying an object, you get an
error. In this case, the error message is not very helpful:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> has_key('one')
NameError: name 'has_key' is not defined
\end{pythonInteractive}
\end{minipage}

\section{Aliasing and copying}
Because dictionaries are mutable, you need to be aware of
aliasing. Whenever two variables refer to the same object, changes to
one affect the other.
If you want to modify a dictionary and keep a copy of the original,
use the \pythoninline{copy} method. For example,
\pythoninline{opposites} is a
dictionary that contains pairs of opposites: 

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> opposites = {'up': 'down', 'right': 'wrong', 'true': 'false'}
>>> alias = opposites
>>> copy = opposites.copy()
\end{pythonInteractive}
\end{minipage}
\pythoninline{alias} and \pythoninline{opposites} refer to the same
object; \pythoninline{copy} refers to a fresh copy of the same
dictionary. If we modify \pythoninline{alias},
\pythoninline{opposites} is also changed: 

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> alias['right'] = 'left'
>>> opposites['right']
'left'
\end{pythonInteractive}
\end{minipage}
If we modify \pythoninline{copy}, \pythoninline{opposites} is unchanged:

\begin{minipage}{\textwidth}
\begin{python}
>>> copy['right'] = 'privilege'
>>> opposites['right']
'left'
\end{python}
\end{minipage}

\section{Sparse matrices}
\brenNote{I don't think sparse matrices are a great example of using
dictionaries. Dictionaries are incredibly useful things - why waste
such a good opportunity to highlight their usefulness. OTOH - it gives
us a rich set of exercises to set:-)}

We previously used a list of lists to represent a matrix. That is a
good choice for a matrix with mostly nonzero values, but consider a
sparse matrix like this one:

\includegraphics[scale=1]{illustrations/sparse.png}

The list representation contains a lot of zeroes:

\begin{minipage}{\textwidth}
\begin{python}
matrix = [ [0,0,0,1,0],
   [0,0,0,0,0],
   [0,2,0,0,0],
   [0,0,0,0,0],
   [0,0,0,3,0] ]
\end{python}
\end{minipage}
An alternative is to use a dictionary. For the keys, we can use
tuples that contain the row and column numbers. Here is the
dictionary representation of the same matrix:

\begin{minipage}{\textwidth}
\begin{python}
matrix = {(0,3): 1, (2, 1): 2, (4, 3): 3}
\end{python}
\end{minipage}
We only need three key-value pairs, one for each nonzero element of
the matrix. Each key is a tuple, and each value is an integer.
To access an element of the matrix, we could use the \pythoninline{[]}
operator: 

\begin{minipage}{\textwidth}
\begin{python}
>>> matrix[(0, 3)]
1
\end{python}
\end{minipage}
Notice that the syntax for the dictionary representation is not the
same as the syntax for the nested list representation. Instead of two
integer indices, we use one index, which is a tuple of integers.
There is one problem. If we specify an element that is zero, we get
an error, because there is no entry in the dictionary with that key:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> matrix[(1, 3)]
KeyError: (1, 3)
\end{pythonInteractive}
\end{minipage}
The \pythoninline{get} method solves this problem:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> matrix.get((0, 3), 0)
1
\end{pythonInteractive}
\end{minipage}
The first argument is the key; the second argument is the value get
should return if the key is not in the dictionary:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> matrix.get((1, 3), 0)
0
\end{pythonInteractive}
\end{minipage}
\pythoninline{get} definitely improves the semantics of accessing a sparse
matrix. Shame about the syntax.


\section{Counting letters}
In Lecture \ref{lec-strings}, we wrote a function that counted the number of
occurrences of a letter in a string. A more general version of this
problem is to form a histogram of the letters in the string, that is,
how many times each letter appears.
Such a histogram might be useful for compressing a text file. Because
different letters appear with different frequencies, we can compress
a file by using shorter codes for common letters and longer codes for
letters that appear less frequently.

Dictionaries provide an elegant way to generate a histogram:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> letter_counts = {}
>>> for letter in "Mississippi":
...   letter_counts[letter] = letter_counts.get(letter, 0) + 1
...
>>> letter_counts
{'M': 1, 's': 4, 'p': 2, 'i': 4}
\end{pythonInteractive}
\end{minipage}
We start with an empty dictionary. For each letter in the string, we
find the current count (possibly zero) and increment it using the
\pythoninline{get} method. At the end,
the dictionary contains pairs of letters and their frequencies.
It might be more appealing to display the histogram in alphabetical
order. We can do that with the \pythoninline{items} and
\pythoninline{sort} methods: 

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> letter_items = letter_counts.items()
>>> letter_items.sort()
>>> print letter_items
[('M', 1), ('i', 4), ('p', 2), ('s', 4)]
\end{pythonInteractive}
\end{minipage}
The \pythoninline{sort} method is one of several that can be applied
to lists, others include
\pythoninline{append}, \pythoninline{extend}, and
\pythoninline{reverse}. Consult the Python documentation for details. 

\section{Glossary}
\begin{description}
\item[dictionary:]A collection of key-value pairs that maps from keys
   to values. The keys can be any immutable type, and the values can
   be any type.
\item[key:]A value that is used to look up an entry in a dictionary.
  Keys must be of an immutable type (e.g. integer, float, string, tuple).
\item[key-value pair:]One of the items in a dictionary.
\item[invoke:]To call a method.
\item[hint:]Temporary storage of a precomputed value to avoid
   redundant computation.
\end{description}

\newpage
\section{Laboratory exercises}
\label{sec-labs-dicts}
\begin{enumerate}
 \item \label{string-histogram}
   Write a program that reads in a string and
   returns a table of the letters of the alphabet in alphabetical
   order which occur in the string together with the number of times
   each letter occurs. Case should be ignored. A sample run of the
   program would look this this:

\begin{minipage}{\textwidth}
\begin{pythonOutput}
Enter a string: > ThiS is String with Upper and lower case Letters.
a  2
c  1
d  1
e  5
g  1
h  2
i  4
l  2
n  2
o  1
p  2
r  4
s  5
t  5
u  1
w  2
\end{pythonOutput}
\end{minipage}

\item \label{file-histogram} Write another program that reads from a file and produces a
  similar output to that in question \ref{string-histogram}.

\item Write a function called \pythoninline{matrix\_to\_sparse}
  that takes a matrix represented as a nested list as specified in
  Section \ref{sec-matrices-nested} as input, and returns a sparse
  matrix represented as a dictionary.

\item Write a function called \pythoninline{sparse\_to\_matrix}, that
  takes a sparse matrix represented as a dictionary, and returns a
  matrix represented as a nested list as in Section
  \ref{sec-matrices-nested}.
 
\item In Exercise \ref{matrix-mult} in Lecture \ref{lec-lists2} you
  wrote a function to multiply two matrices that were represented as
  nested lists. Write another function called
  \pythoninline{matrix\_mult\_sparse}, that takes two sparse matrices,
  represented using dictionaries, and returns a sparse matrix which is
  the product of the two input matrices.
\end{enumerate}


