#!/usr/bin/python3 # -*- coding: utf-8 -*- """ Dictionaries are mutable, and store mappings from keys to values, i.e., {K: V} Keys are a set of unique single keys and map to potentially multiple value(s) More than one entry per key is not allowed. This means no duplicate keys are allowed. However, one key can have multiple values stored. """ from typing import Dict, List, Tuple, Union help(dict) # %% Dictionaries # Create an empty dictionary: empty_dict = {} # Can also create this way: empty_dict = dict() # Here is a filled dictionary # Dict[key, val] filled_dict: Dict[str, int] = {"one": 1, "two": 2, "three": 3} # Note keys for sets and dictionaries have to be immutable types. # This is to ensure that the key can be converted to a # constant hash value for quick look-ups. # Immutable types include ints, floats, strings, tuples, frozensets print("Type: invalid_dict = {[1, 2, 3]: '123'}") # invalid_dict = {[1, 2, 3]: "123"} # => Raises a TypeError: unhashable type: 'list' valid_dict: Dict[Tuple[int, int, int], List[int]] = {(1, 2, 3): [1, 2, 3]} # Values can be of any type, however. # [] looks up keys, and returns values filled_dict["one"] # => 1 # Get all keys as an iterable with "keys()". # We need to wrap the call in list() to turn it into a list. # We'll talk about those later. # Note - for Python versions <3.7, dictionary key ordering is not guaranteed. # Your results might not match the example below exactly. # However, as of Python 3.7, dictionary items maintain the order # in which they are inserted into the dictionary. print(filled_dict) print(list(filled_dict.keys())) # => ["three", "two", "one"] in Python <3.7 print(list(filled_dict.keys())) # => ["one", "two", "three"] in Python 3.7+ # Get all values as an iterable with "values()". # Once again we need to wrap it in list() to get it out of the iterable. # Note - Same as above regarding key ordering. print(filled_dict) print(list(filled_dict.values())) # => [3, 2, 1] in Python <3.7 print(list(filled_dict.values())) # => [1, 2, 3] in Python 3.7+ # Check for existence of a key in a dictionary with "in" print("one" in filled_dict) # => True print(1 in filled_dict) # => False # Note: we don't look up values in a dictionary - That's not their purpose! # Looking up a non-existing key is a KeyError print("Type: filled_dict['four']") # KeyError # filled_dict["four"] # KeyError # KeyError: 'four' # Use "get()" method to avoid the KeyError print(filled_dict.get("one")) # => 1 print(filled_dict.get("four")) # => None # The get method supports a default return when the value is missing print(filled_dict.get("one", 4)) # => 1 print(filled_dict.get("four", 4)) # => 4 # "setdefault()" inserts into a dictionary only if the given key isn't present filled_dict.setdefault("five", 5) # filled_dict["five"] is set to 5 filled_dict.setdefault("five", 6) # filled_dict["five"] is still 5 print(filled_dict) # Adding to a dictionary filled_dict.update({"four": 4}) # => {"one": 1, "two": 2, "three": 3, "four": 4} print(filled_dict) filled_dict["four"] = 4 # another way to add to dict # Note: most of the time, this is the best. # Remove keys from a dictionary with del del filled_dict["one"] # Removes the key "one" from filled dict # From Python 3.5 you can also use the additional unpacking options # ** un-packs a dictionary into pairs print({"a": 1, **{"b": 2}}) # => {'a': 1, 'b': 2} print({"a": 1, **{"a": 2}}) # => {'a': 2} # Key must be hashable, and immutable # Dictionaries are mutable, and hashable, # so can be contained as keys in dictionaries. # There are some libraries, like networkx, # that are entirely nested dictionaries! # Several ways to initialize: onedict: Dict[str, str] = dict(Bobby="805-555-2232", Johnny="951-555-0055") # This is probably the most useful/common way: phonebook: Dict[str, int] = {} phonebook["John"] = 938477566 phonebook["Jack"] = 938377264 phonebook["Jill"] = 947662781 print(phonebook) print(phonebook["Jill"]) # get takes key, and "default" print(phonebook.get("Jill", "Not there")) print(phonebook.get("Bob", "Not there")) phonebook = {"John": 938477566, "Jack": 938377264, "Jill": 947662781} print(phonebook) # in checks against keys, not values print("John" in phonebook) print(947662781 in phonebook) # The purpose of hash tables is quick key lookup # This is an alternate (slow) print("John" in phonebook.keys()) # This operation will be slow: print(947662781 in phonebook.values()) # delete deletes the whole entry del phonebook["John"] print(phonebook) # pop returns the deleted value (not entry pair) popped: int = phonebook.pop("Jill") print(phonebook) print(popped) # Heterogeneous keys: adict: Dict[Union[str, int], str] = {} adict["one"] = "This is one" adict[2] = "This is two" print(adict["one"]) # Prints value for 'one' key print(adict[2]) # Prints value for 2 key tinydict: Dict[str, Union[str, int]] = {"name": "john", "code": 6734, "dept": "sales"} print(tinydict) # Prints complete dictionary print(tinydict.keys()) # Prints all the keys print(tinydict.values()) # Prints all the values # Deleting and clearing entries and the whole dictionary: anotherdict = {"Name": "Zara", "Age": 7, "Class": "First"} print("Name" in anotherdict) del anotherdict["Name"] # remove entry with key 'Name' print("dict['Age']: ", anotherdict["Age"]) anotherdict.clear() # remove all entries in dict del anotherdict # delete entire dictionary # looping dicts d: Dict[str, float] = {"a": 1, "b": 1.2, "c": 1.4} print(d.items()) print(d.keys()) print(d.values()) for key, val in sorted(d.items()): print("Key: %s has value: %s" % (key, val)) for key in d: print("Key: %s has value: %s" % (key, d[key])) for key in d: print("Key: %s has value: %s" % (key, d.get(key))) for anothervalue in d.values(): print(anothervalue) for key in d.keys(): print(key)