Mappings : The dict

A mapping is an association (or “link”) from one object to another. A real dictionary, for example, maps a defintion to a word. Note that this is a one-way association; you can’t directly find the word from the definition; you can easily find the definition from the word.

We have to make a subtle distinction between the abstraction (a mapping) and the implementation (a dictionary). Most of the time, you’ll use the only available mapping, the Python dictionary, dict. There are other mappings, however.

We’ll look at what Python means by a Dictionary in What Does Python Mean by “Dictionary”?. We’ll show how to create a Dictionary in How We Create A Dictionary. We’ll look at the various operations we can perform on a Dictionary in Operations We Can Perform On A Dictionary.

We can’t meaningfully compare two dictionaries; we’ll look at this in Comparing Dictionaries – Not A Good Idea. There are a large number of method functions, which we’ll look at in Method Functions That Dictionaries Offer. Some of the statements we’ve already seen interact with dictionaries; we’ll look at this in Statements and Dictionaries. We’ll look at some built-in functions in Built-in Functions for Dictionaries.

What Does Python Mean by “Dictionary”?

A dict maps a key to a value. In the big red-covered paper dictionary on my bookshelf, the key is a word, and the value is complex object, including a pronunciation guide, a definition, and an etymology.

Mappings are unidirectional, unordered collections. Each element is identified by a key. A dictionary represents a kind of space-time tradeoff.

Here’s a depiction of a dictionary of 3 items. The keys are string color names, and the values are numeric color levels. This dictionary is one way to describe a nice midnight-blue. In his case, the keys are all strings and the values are all numbers.

>>> color= {"RED":51, "GREEN":0, "BLUE":153}
key value
RED 51
GREEN 0
BLUE 153

We’ll look at the features of a dictionary in some detail.

Unidirectional. A mapping is unidirectional, from key to value; you can’t easily locate the key given the value. Also, note that each key occurs exactly once in the mapping. Values can occur more than once.

The mapping associates a value with a key. Locating a key from a value is not supported.

>>> color['RED']
51
>>> color[153]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 153

Unordered. A simple dict cannot preserve order. This is because it uses a hashing algorithm to identify a place in the dict for a given key. Every Python object must have a hash value: a simple distinct number. Objects, like strings or tuples, have hash values which summarize the string or tuple as a unique numeric value. The built-in function, hash() is used to do this calculation.

>>> color
{'BLUE': 153, 'GREEN': 0, 'RED': 51}

We created the dictionary in one order, Python shows us the dictionary in a different order.

Collection. A dictionary, like the sequences we looked at in Basic Sequential Collections of Data, is a kind of collection of objects. Since the dictionary as a whole is mutable, items can be inserted into the dict, found in the dict and removed from the dict.

>>> color['GREEN']= 16
>>> color
{'BLUE': 153, 'GREEN': 16, 'RED': 51}

A dict object has member methods that return a sequence of keys, a sequence of values, or a sequence of ( key , value ) tuples suitable for use in a for statement.

>>> color.keys()
['BLUE', 'GREEN', 'RED']
>>> color.items()
[('BLUE', 153), ('GREEN', 16), ('RED', 51)]

Immutable Keys. Above, we noted the mutability restriction on the key. The key object must compute a consistent hash value. This issue of consistency is important. If the key changes, how can we identify it in the dictionary?

For the immutable built-in types, the hash value is perfectly consistent: numbers, strings, tuples and frozensets are all good kinds of keys for a dictionary.

The mutable types – like lists, sets or dictionaries – present an obvious difficulty if their value should change.

However, you can “freeze” a list by making a tuple copy of it; similarly, you can freeze a set by making a frozenset copy of it.

Space vs. Time. We used the mathematical term “map” to define what a function does, back in Adding New Verbs : The def Statement. When we define a function, we write an algorithm which is, in effect, the mapping from the domain values to the range values. In a dictionary, Python explicitly stores a specific set of domain values and their associated range values.

A function like square root, for example, can map any positive floating-point number to that number’s square root. We don’t store all of the billions of possible floating-point numbers, instead the math.sqrt() function computes a mapping for each specific argument value using an algorithm. A function uses less storage, but is rather slow.

In the case of a dictionary, we can associate some specific floating-point numbers with their square roots. We don’t have a completely general algorithm, just a list of keys and their associated values. This will use a considerable amount of storage, but will be very, very fast.

Other Mappings? We have to emphasize a terminology issue here. Python has provisions for creating a variety of different types of mappings. Only one type of mapping comes built-in; that type is the dict. The term mapping and dictionary are almost interchangeable.

In Another Mapping : The defaultdict, we’ll look at another variety of mapping, called collections.defaultdict. This is a slightly different mapping. It’s a dictionary, but with some extra features.

Python 3 will add the collections.OrderedDict class.

How We Create A Dictionary

A dictionary literal is created by surrounding a sequence of key : value pairs with { }`, and separating each key : value pair with ,s. An empty dictionary is { }.

Here are some examples. We’ll describe each dictionary in detail, below.

wheel = { 0:"green", "00":"green",
 1:"red", 2:"black", 3:"red",
 4:"black", 5:"red", 6:"black" }
myBoat = { "NAME":"KaDiMa", "LOA":18,
 "SAILS":["main","jib","spinnaker"] }
theBets = { }
diceRoll = { (1,1): "snake eyes", (6,6): "box cars" }
wheel:This dictionary has eight elements. Most of the elements have a number as their key; one of the elements has a string as the key. All the elements have a string as the value.
myBoat:The myBoat dictionary has three elements. One element has a key of the string "NAME" and a value of the string "KaDiMa". Another element has a key of the string "LOA" and a value of the integer 18. The third element has a key of the string "SAILS" and the value of a list ["main", "jib", "spinnaker"].
theBets:The theBets is an empty dictionary.
diceRoll:The diceRoll variable is a dictionary with two elements. One element has a key of a tuple (1,1) and a value of a string, "snake eyes". The other element has a key of a tuple (6,6) and a value of a string "box cars".

Dictionary items and keys do not have to be the same type. Keys must be a type that can produce a hash value. Since lists, sets and dictionary objects are mutable, they are not permitted as keys. All other non-mutable types (especially strings and tuples) are legal keys.

Dictionary Factory Function. In addition to literal values, the following function also creates a dictionary object.

dict(mapping) → dictionary

Creates a dictionary from the items in mapping. If the mapping is omitted, an empty dictionary is created.

dict(sequence) → dictionary

Creates a dictionary from the items in sequence. Each item in the sequence must be a two-tuple with keys and values. For example,

dict( [ ('akey','the value'), ('key2','a value') ] )
dict(param=value, ...) → dictionary

Creates a dictionary from the named parameters. Each parameter name becomes a key, and each parameter value becomes a value. For example

dict( akey='the value', key2='a value')

This only works when the keys are strings which satisfy the rules for Python variable names.

Operations We Can Perform On A Dictionary

Dictionaries have two operations: [] and %. The [] operator is similar to the other collection types, it is used to add, change or retrieve individual items from the dictionary.

The [] operator. The [] operator can identify a single value in the dictionary based on the key value. This operator does the key-to-value mapping for the dictionary. When we have a statement like dictionary[key] = value, we are updating the dictionary. When we use :dictionary[key] in an expression, we are looking something up in the dictionary.

Examples of dictionary operations.

>>> boat1={}
>>> boat1["NAME"]= "KaDiMa"
>>> boat1["SAILS"]= ["main","jib","spinnaker"]
>>> boat1["LOA"]= 15
>>> boat1["LOA"]= 18
>>> boat1
{'SAILS': ['main', 'jib', 'spinnaker'], 'LOA': 18, 'NAME': 'KaDiMa'}
>>> boat1["NAME"]
'KaDiMa'
>>> boat1["BEAM"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'BEAM'

This example starts by creating an empty dictionary, boat1. We provide a key of "NAME" and a value of "KaDiMa" , which updates the dictionary. We provide a key of "SAILS" and a value which is a list, ["main","jib","spinnaker"]. We also set the value 15 for the key "LOA"; this turns out to be incorrect, so we replaced the 15 with an 18.

When we ask for the value of boat1, the dictionary is displayed, showing the key:value pairs. Notice that the order does not correlate to the order in which we entered keys and values.

When we evaluate boat1["NAME"], we see the value that is associated with this key.

When we evaluate boat1["BEAM"], we see that any attempt to access a missing key gives us a KeyError exception.

Here are some other examples of picking elements out of a dictionary. In this case, we get the list value and use it in a for statement.

>>> for s in boat1["SAILS"]:
...     print(s)
...
main
jib
spinnaker

The % Operator. The string format operator works between string and dictionary. We prefer to use str.format(), however.

The string formatting method, str.format() can be applied to a dictionary as well as a sequence.

When this operator was introduced in Sequences of Characters : str and Unicode, the format specifications were applied to values from a sequence. We named the values by providing a simple position number. The format specification of {0:d} used the first value, the one at position zero. The format {1:5.2f} used the value at position one.

When we apply the format specifications to values that include dictionary, each format specification can include a dictionary key to pick a specific item from within the dictionary. We can use the position number along with the dictionary key in a syntax like {0[LOA]:d}. In this case item zero in the format arguments is expected to be a dictionary and the key value "LOA" will be the item that gets formatted.

For example:

>>> myBoat= { "NAME": "Red Ranger", "LOA": 42 }
>>> "{0[NAME]}, {0[LOA]:d} feet".format( myBoat )
'Red Ranger, 42 feet'

This will find myBoat[NAME] and use default formatting; it will find myBoat[LOA] and use d number formatting.

We can also provide a dictionary as the only argument to the format method. There are two ways to do this. We’ll show more of this in A Dictionary of Extra Keyword Values.

The dict() function can build a dictionary from arguments where specific parameter names are provided. We can use key=value to build a dictionary when the key’s are strings that follow Python variable name rules.

>>> dict( NAME="Red Ranger", LOA=42 )
{'LOA': 42, 'NAME': 'Red Ranger'}

The arguments to all functions follow this rule. Because the arguments to the str.format() method follow these standard rules, we can provide values in the form of a dictionary.

Consider this example:

>>> "{NAME}, {LOA:d} feet".format( NAME="Red Ranger", LOA=42 )
'Red Ranger, 42 feet'

The arguments to the str.format() method become a dictionary. The keys are used directly in the format strings.

Comparing Dictionaries – Not A Good Idea

Some of the standard comparisons (<, <=, >, >=, ==, !=) don’t have a lot of meaning between two dictionaries. There may be no common keys, nor even a common data type for keys or values. Since there is no real basis for comparison, dictionaries are simply compared by length. The dictionary with fewer elements is considered to be less than a dictionary with more elements.

The membership comparisons (in, not in) apply to the keys of a dictionary.

>>> diceRoll = { (1,1): "snake eyes", (6,6): "box cars" }
>>> (1,1) in diceRoll
True
>>> diceRoll[(1,1)]
'snake eyes'
>>> (2,1) in diceRoll
False
>>> diceRoll[(2,1)]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: (2, 1)
>>> (2,1) not in diceRoll
True

If you want to work with the values, you have to use the values() method of the dictionary.

>>> wheel = { 0:"green", "00": "green",
 1:"red", 2:"black", 3:"red",
 4:"black", 5:"red", 6:"black" }
>>> "red" in wheel.values()
True
>>> "blue" in wheel.values()
False

Method Functions That Dictionaries Offer

A dictionary object has a number of method functions. These can be grouped arbitrarily into transformations, which change the dictionary, and accessors, which returns a fact about a dictionary.

Manipulators. The following manipulators make changes to a dictionary. With the exception of setdefault(), these methods do not return a value.

class dict
dict.clear()

Remove all items from the dictionary.

>>> freq= { 'red':470, 'green':52, 'black':478 }
>>> freq.clear()
>>> freq
{}
dict.setdefault(key, value) → object

Similar to get() and d[key]; get the item with the given key. However, this sets the supplied default in the dictionary, if the key did not exist. If no value is given for default, the value None is used.

>>> wheel= 18*['black']+18*['red']+2*['green']
>>> freq= { }
>>> color= random.choice(wheel)
>>> freq.setdefault( color, 0 )
0
>>> freq[color] += 1
>>> freq
{'red': 1}
dict.update(new)

Merge values from the new dictionary into the original dictionary, adding or replacing as needed. It is equivalent to the following Python statement. for k in new.keys(): d[k]= new[k].

Accessors. The following accessors determine a fact about a dictionary and return that as a value.

class dict
dict.copy() → dictionary

Copy the dictionary to make a new dictionary. This is a shallow copy. All objects in the new dictionary are references to the objects in the original dictionary.

dict.get(key[, default]) → object

Get the item with the given key, similar to d[key]. If the key is not present, supply default instead. If no value is given for default, the value None is used.

>>> freq= { 'red':470, 'green':52, 'black':478 }
>>> freq.get('red','N/A')
470
>>> freq.get('white','N/A')
'N/A'
>>> freq['red']
470
>>> freq['white']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'white'
dict.has_key(key)

If there is an entry in the dictionary with the given key, return True, otherwise return False.

This is usually written key in dictionary. The dictionary.has_key( key ) form isn’t used very often.

>>> freq= { 'red':470, 'green':52, 'black':478 }
>>> freq.has_key('red')
True
>>> freq.has_key('white')
False
>>> 'red' in freq
True
dict.items() → sequence

Return all of the items in the dictionary as a sequence of ( key , value ) tuples. Note that these are returned in no particular order.

>>> freq= { 'red':470, 'green':52, 'black':478 }
>>> freq.items()
[('black', 478), ('green', 52), ('red', 470)]
dict.keys() → sequence

Return all of the keys in the dictionary as a sequence of keys. Note that these are returned in no particular order.

>>> freq= { 'red':470, 'green':52, 'black':478 }
>>> freq.keys()
['black', 'green', 'red']
dict.values() → sequence

Return all the values from the dictionary as a sequence. Note that these are returned in no particular order.

>>> freq= { 'red':470, 'green':52, 'black':478 }
>>> freq.values()
[478, 52, 470]

Statements and Dictionaries

We can look at three statements and how they make use of dictionaries: the for statement and the del statement.

The for statement. The for statement uses an iterator to step through each value in a given sequence. A dictionary responds to the iterator protocol by iterating through the keys of a dictionary.

>>> monDict = { "JAN":1, "FEB":2, "MAR":3, "APR":4, "MAY":5, "JUN":6 }
>>> for d in monDict:
...     print(d, monDict[d])
...
MAR 3
FEB 2
APR 4
JUN 6
JAN 1
MAY 5

Notice that the keys are provided in no particular order. The dictionary is optimized for raw speed, and this means that they keys can be scrambled.

We can use the sorted() function to handle this.

>>> monDict = { "JAN":1, "FEB":2, "MAR":3, "APR":4, "MAY":5, "JUN":6 }
>>> for k in sorted(monDict):
...     print(k, monDict[k])
...
APR 4
FEB 2
JAN 1
JUN 6
MAR 3
MAY 5

Additional for techniques. Additionally, we can use several dictionary method functions to extract a sequence of values from the dictionary. We’ll look at items(), keys() and values().

Because of for statement works with multiple assignment, and the items() method function returns a sequence of tuples, we have a powerful technique for iterating through a dictionary. For example

>>> monDict = { "JAN":1, "FEB":2, "MAR":3, "APR":4, "MAY":5, "JUN":6 }
>>> for name, number in monDict.items():
...     print(number, name)
...
3 MAR
2 FEB
4 APR
6 JUN
1 JAN
5 MAY

The items() method of the dictionary named monDict returns a sequence with each entry transformed to a ( key , value ) tuple. The multiple assignment in the for statement assigns the keys to name and the values to number as it iterates through each element of the sequence. Note that the values returned bear little relationship to the order in which the dictionary was created.

The del statement. The del statement removes items from a dictionary. For example

>>> i = { "two":2, "three":3, "quatro":4 }
>>> del i["quatro"]
>>> i
{'two': 2, 'three': 3}

In this example, we removed a key (and it’s associated value) from a dictionary by specifying which key we wanted removed.

Built-in Functions for Dictionaries

A number of built-in functions create or deal with dictionaries. The following functions apply to all collections, including dictionaries.

len(iterable) → integer

Return the number of items in the iterable (set, sequence or mapping).

>>> wheel = { 0:"green", "00": "green",
 1:"red", 2:"black", 3:"red",
 4:"black", 5:"red", 6:"black" }
>>> len(wheel)
8
max(dictionary) → value

Returns the greatest key in the dictionary.

>>> diceRoll = { (1,1): "snake eyes", (6,6): "box cars" }
>>> max(diceRoll)
(6, 6)

Since our keys are a variety of types (strings and ints), the max() comparison is somewhat unexpected.

min(dictionary) → value

Returns the least key in the dictionary.

>>> diceRoll = { (1,1): "snake eyes", (6,6): "box cars" }
>>> max(diceRoll)
(1, 1)

If you want to apply max() or min() to the values instead of the keys, you’ll use the values() method. It would look like this.

>>> a = { 23:'skidoo', 7:'eleven', 4:'ever' }
>>> max(a)
23
>>> max(a.keys())
23
>>> max(a.values())
'skidoo'

Generally, functions like sum(), any() and all() don’t make a lot of sense when applied to the keys of a dictionary. You often apply these to the values, however.

Iteration Functions. These functions are most commonly used with a for statement to process dictionary keys.

enumerate(iterable) → iterator

Enumerate the elements of a set, sequence or mapping. This yields a sequence of tuples based on the original tuple. Each of the result tuples has two elements: a sequence number and the key from the original dictionary.

Since dictionaries have no guaranteed ordering, this isn’t completely sensible.

This is generally used with a for statement. Here’s an example:

>>> freq= { 'red':470, 'green':52, 'black':478 }
>>> for position, color in enumerate(freq):
...     print(position, color, freq[color])
...
0 black 478
1 green 52
2 red 470

Note that the order as enumerated is not the order originally entered.

sorted( iterable [,key] [,reverse] ) → iterator

This iterates through an iterable object like the keys of a mapping in ascending or descending sorted order. Unlike a list’s sort() method function, this does not update the map, but leaves it alone.

This is generally used with a for statement. Here’s an example:

>>> freq= { 'red':470, 'green':52, 'black':478 }
>>> for color in sorted( freq ):
...     print(color, freq[color])
...
black 478
green 52
red 470

Producing output sorted by value is a bit trickier. The keys must be unique, but the values don’t have to be unique. That makes it impossible to determine which key belongs to a value.

What we do to report on a dictionary in value order is to use the list of tuples representation produced by the items() method.

>>> freq= { 'red':470, 'green':52, 'black':478 }
>>> freq.items()
[('black', 478), ('green', 52), ('red', 470)]
>>> def by_freq( freq_pair ): return freq_pair[1]
...
>>> sorted( freq.items(), key=by_freq )
[('green', 52), ('red', 470), ('black', 478)]
reversed(iterable) → iterator

This iterates through an iterable (set, sequence, mapping) in reverse order.

Since dictionaries have no guaranteed ordering, this isn’t completely sensible.

This is generally used with a for statement.

Aggregation Functions. These functions reduce a dictionary to a single aggregate value.

sum(iterable) → number

Sum the values in the iterable (set, sequence, mapping). All of the values must be numeric.

When applied to a mapping, this will sum the keys. More commonly, we want to sum the values.

>>> freq= { 'red':470, 'green':52, 'black':478 }
>>> sum( freq.values() )
1000
all(iterable) → boolean

Return True if all values in the iterable (set, sequence, mapping) are equivalent to True.

When applied to a mapping, this will test the keys. More often we will use a Generator Expression, which allows us to apply the all test to the values.

>>> myBoat = { "NAME":"KaDiMa", "LOA":18, "HULL":"mono",
...      "SAILS":["main","jib","spinnaker"] }
>>> all( v is not None for v in myBoat.values() )
True
any(iterable) → boolean

Return True if any value in the iterable (set, sequence, mapping) is equivalent to True.

When applied to a mapping, this will test the keys. More often we will use a Generator Expression, which allows us to apply the any test to the values.

>>> fireSail = { "NAME":None, "LOA":16, "HULL":"catamaran",
...      "SAILS":["main","jib"] }
>>> any( v is None for v in fireSail.values() )
True

Dictionary Exercises

  1. Word Frequencies.

    A string can be split into individual words using the string’s split() method. A dictionary can be used to accumulate the list of words and their frequency.

    By default, a string’s split() method will break up the string on the spaces, giving us a sequence of individual words. Each word will have attached punctuation marks, something that is difficult to process without more powerful tools. For now, we’ll tolerate the punctuation at the end of some words.

    import string
    
    myText= """Call me Ishmael.  Some years ago -- never mind how long
    precisely -- having little or no money in my purse, and nothing
    particular to interest me on shore, I thought I would sail about a
    little and see the watery part of the world."""
    words= myText.split()
    

    Iterate through this sequence, placing each word into a dictionary. The first time a word is seen, the frequency should be set to 1. Each time the word is seen again, increment the frequency. The final dictionary will be a frequency table.

    To alphabetize the frequency table, extract just the keys. A sequence can be sorted (see Flexible Sequences : The list). This sorted sequence of keys can be used to extract the counts from the dictionary.

  2. Stock Reports.

    A block of publicly traded stock has a variety of attributes, we’ll look at a few of them. A stock has a ticker symbol and a company name. Create a simple dictionary with ticker symbols and company names.

    For example:

    stockDict = { 'GM': 'General Motors',
     'CAT':'Caterpillar', 'EK':"Eastman Kodak" }
    

    Create a simple list of blocks of stock. These could be tuples with ticker symbols, prices, dates and number of shares. For example:

    purchases = [ ( 'GE', 100, '10-sep-2001', 48 ),
    ( 'CAT', 100, '1-apr-1999', 24 ),
    ( 'GE', 200, '1-jul-1998', 56 ) ]
    

    Create a purchase history report that computes the full purchase price (shares times dollars) for each block of stock. Use the full company names in stockDict to look up the full company name. This is the basic relational database join algorithm between two tables.

    The outline of processing looks like this:

    for s in purchases:
    
        look up s[0] in  stockDict
    
        compute shares \times price
    
        print a nice-looking line
    

    Create a second purchase summary that which accumulates total investment by ticker symbol. In the above sample data, there are two blocks of GE stock. These can be combined by creating a dictionary where the key is the ticker and the value is a list of blocks that have a common ticker symbol.

    The outline of the processing looks like this:

    blocks = {}
    for s in purchases:
        symbol= s[0]
        if  symbol in blocks:
            Append this block to the list blocks[symbol]
        else:
            Create a 1-element list in blocks[symbol]
    

    A pass through the resulting dictionary can then create a report showing each ticker symbol and all blocks of stock. The outline of the processing looks like this:

    for symbol,blockList in blocks.items():
        totalValue= 0
        totalShares= 0
        for s in blockList:
            compute value as shares \times price
            accumulate value in totalValue
            accumulate shares in totalShares
        print a nice-looking line showing totals
    
  3. Date Decoder.

    A date of the form 8-MAR-85 includes the name of the month, which must be translated to a number. Create a dictionary suitable for decoding month names to numbers. Create a function which uses string operations to split the date into 3 items using the “-” character. Translate the month, correct the year to include all of the digits.

    The function will accept a date in the “dd-MMM-yy” format and respond with a tuple of ( y, m, d ).

  4. Dice Odds.

    There are 36 possible combinations of two dice. A simple pair of loops over range(6)+1 will enumerate all combinations. The sum of the two dice is more interesting than the actual combination. Create a dictionary of all combinations, using the sum of the two dice as the key.

    Each value in the dictionary should be a list of tuples; each tuple has the value of two dice. The general outline is something like the following:

    d= {}
    Loop with d1 from 1 to 6
        Loop with d2 from 1 to 6
            newTuple = ( d1, d2 ) # create the tuple
            oldList = d[ d1+d2 ]
            newList = oldList + newTuple
            d[ d1+d2 ] = newList
    
    Loop over all values in the dictionary
        print the key and the length of the list

Mapping FAQ’s

If there’s only one kind of mapping, the dictionary, why make a distinction between the two terms?

Currently, there’s only one built-in mapping, which is the dictionary. However, proposals are regularly floated around to add the “ordered dictionary” as a second kind of mapping. This other kind of mapping would use the Red-Black Tree algorithms to create a kind of mapping which would be somewhat slower than the hashed dictionary we have now, but would guarantee that they keys were always kept in order.

Also, in Another Mapping : The defaultdict, we’ll look at another kind of dictionary, the default dictionary. It’s not built-in, but it’s widely used.

The word “map” seems to have a lot of meanings.

If you’re used to a map being a piece of paper that depicts land-masses, then I suppose this new use of map may be unusual. However, we’re using map in the sense of route or path. If you think of someone mapping out their future, they are creating a route from where they are to where they want to be.

Mathematicians use the word map in this sense of association between two objects. They often use these term when defining a function which maps values between the domain and the range. Python folks borrowed this definition of map to talk about how a dictionary maps a key to a value. Further, as a kind of loop design, the mapping is very common

Indeed, much of programming involves associations between values and transformations from one representation of the value (a string, for example) to another representation (like a number). We lump all of this under “mapping” because we may implement it in the style of functions or in the style of a dictionary. It could be an algorithm which computes the range value from the domain value(s). It could, on the other hand, be a data structure that simply provides the domain value associated with the range value.

What if I don’t have a single key for my dictionary?

Let’s say I want a phone book with last names and phone numbers as keys? What do I do then?

Great question. The database designers call this a secondary index. We want to have two different sets of keys for the same individual phone book objects. We can do this by creating a second dictionary with our alternate key.

Let’s assume we have a list of tuples that looks like the following.

names= [ ( "last name", "first name", "phone number" ),
  ( "Howard", "Moe", "555-1111" ),
  ( "Howard", "Shemp", "555-2222" ),
  ( "Fine", "Larry", "555-3333" ), ]

We might want to turn this into two dictionaries doing something like the following. This will decompose the list into the individual name tuples, and assign each tuple to nameTuple. We can associate this tuple object in two different dictionaries. In this example, we’ll assign the tuple to byName and byPhone.

byName = dict()
byPhone= dict()
for nameTuple in names:
    ln, fn, ph = nameTuple
    byName[ln]= nameTuple
    byPhone[ph]= nameTuple

Table Of Contents

Previous topic

Collecting Items : The set

Next topic

Defining More Flexible Functions with Mappings

This Page