Prof. Andrea Gallegati
... like a lists, but more general.
The indices have not to be integers, but can be rather (almost) any type.
A collection of indices (aka keys), each associated with a single value.
Each item (the association) is called a key-value pair.
In mathematical language, this represents a (keys to values) mapping.
An actual dictionary maps from English to Spanish words, for example.
dict
creates a new dictionary with no items: thus, avoid using it for a variable name!
eng2sp = dict()
eng2sp
{}
{}
are an empty dictionary.[]
to add items to the dictionary.eng2sp['one'] = 'uno'
This item maps 'one'
into 'uno'
.
Printing the dictionary, a colon separates the key-value pair.
eng2sp
{'one': 'uno'}
This output format is also an input format: let's create a new dictionary like this
eng2sp = {'one': 'uno', 'two': 'dos', 'three': 'tres'}
Printing it again, we might be surprised:
eng2sp
{'one': 'uno', 'three': 'tres', 'two': 'dos'}
being the key-value pairs order not the same, in any computer (usually).
In general, it's unpredictable.
Not an issue: dictionary elements are never indexed with integer indices.
We use the keys to look up the corresponding values
eng2sp['two']
'dos'
this always maps into the same value 'dos'
.
No matter what the items order is.
If the dictionaryhas not that key, we get an exception:
eng2sp['four']
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) <ipython-input-13-ab2e10594e13> in <module>() ----> 1 eng2sp['four'] KeyError: 'four'
len
function returns the number of key-value pairs:
len(eng2sp)
3
in
operator tells whether something appears as a key (not a value) in the dictionary:
'one' in eng2sp
True
'uno' in eng2sp
False
To see whether something appears as a value in a dictionary use:
values
method (returns a collection of values)in
operatorvals = eng2sp.values()
'uno' in vals
True
in
operator uses different algorithms for lists and dictionaries.
to count different letters occurrences, in a given a string, there are several ways:
Same computation, but different implementations.
Some implementations are better than others.
An advantage of the dictionary one (for example) is to make room just for the letters that do appear:
def histogram(s):
d = dict()
for c in s:
if c not in d:
d[c] = 1
else:
d[c] += 1
return d
histogram, a statistical term for a collection of counters (or frequencies)
def histogram(s):
d = dict()
for c in s:
if c not in d:
d[c] = 1
else:
d[c] += 1
return d
c
is not in the dictionary, create a new key-value pairc
is already in the dictionary, increment d[c]
h = histogram('brontosaurus')
h
{'a': 1, 'b': 1, 'n': 1, 'o': 2, 'r': 2, 's': 2, 't': 1, 'u': 2}
get
method, takes
returns the corresponding value (to the key)
h = histogram('a')
h.get('a', 0)
1
h.get('b', 0)
0
otherwise, the default one
With this, we can re-write histogram (more concisely)
def histogram(s):
d = dict()
for c in s:
d[c] = d.get(c, 0) + 1
return d
for
loop on a dictionary, traverses the dictionary keys.
def print_hist(h):
for c in h:
print(c, h[c])
h = histogram('parrot')
print_hist(h)
t 1 p 1 a 1 r 2 o 1
... the keys are in no particular order.
def print_hist(h):
for key in sorted(h):
print(key, h[key])
let's use the built-in function sorted
print_hist(h)
a 1 o 1 p 1 r 2 t 1
Given a dictionaryand a key, it's easy to find the corresponding value (aka lookup)
v = d[k]
what about reverse lookup?
... if we have the value and want to find the key:
This function returns the first key that maps into a given value:
def reverse_lookup(d, v):
for k in d:
if d[k] == v:
return k
raise LookupError()
raise
statement causes a LookupError
exception
a built-in to indicate the operation failed: value not in the dictionary.
Here below a successful reverse lookup:
h = histogram('parrot')
k = reverse_lookup(h, 2)
k
'r'
... and an unsuccessful one:
k = reverse_lookup(h, 3)
--------------------------------------------------------------------------- LookupError Traceback (most recent call last) <ipython-input-36-8e509d336cbb> in <module>() ----> 1 k = reverse_lookup(h, 3) <ipython-input-34-7ad83190a369> in reverse_lookup(d, v) 3 if d[k] == v: 4 return k ----> 5 raise LookupError() LookupError:
same effect as when Python raises an exception: it prints
raise
statement can take (an optional) detailed error message:
raise LookupError('value does not appear in the dictionary')
--------------------------------------------------------------------------- LookupError Traceback (most recent call last) <ipython-input-37-126aa63df058> in <module>() ----> 1 raise LookupError('value does not appear in the dictionary') LookupError: value does not appear in the dictionary
reverse lookup is much slower than a forward lookup
the program performances will suffer.
a dictionary may have lists values.
Given a dictionary mapping letters into frequencies, inverting it we might have:
Each value in the inverted dictionary must be a list of letters.
This function inverts a dictionary:
def invert_dict(d):
inverse = dict()
for key in d:
val = d[key]
if val not in inverse:
inverse[val] = [key]
else:
inverse[val].append(key)
return inverse
Each time through the loop:
hist = histogram('parrot')
hist
{'a': 1, 'o': 1, 'p': 1, 'r': 2, 't': 1}
inverse = invert_dict(hist)
inverse
{1: ['t', 'p', 'a', 'o'], 2: ['r']}
These are the state diagrams representing the two dictionaries.
lists are drawn outside the box, to keep the diagram simple
Lists can be values in a dictionary, but they cannot be keys.
t = [1, 2, 3]
d = dict()
d[t] = 'oops'
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-42-487ac70bbf34> in <module>() 1 t = [1, 2, 3] 2 d = dict() ----> 3 d[t] = 'oops' TypeError: unhashable type: 'list'
Dictionaries are implemented using hashtables: the keys have to be hashable.
A hash is a function:
Dictionaries (aka hashtables) use these integers (aka hash values) to store and look up key-value pairs.
Everything works fine if the keys are immutable.
Being the keys mutable (like lists) bad things happen:
Python
hashes the key to store the key-value pair.That’s why mutable types like lists aren’t hashable, while tuples are.
Since dictionaries are mutable, they can’t be used as keys, but they can be used as values!