Skip to content

Latest commit

 

History

History
240 lines (188 loc) · 4.87 KB

python-dict.rst

File metadata and controls

240 lines (188 loc) · 4.87 KB

Dictionary

Get All Keys

>>> a = {"1":1, "2":2, "3":3}
>>> b = {"2":2, "3":3, "4":4}
>>> a.keys()
['1', '3', '2']

Get Key and Value

>>> a = {"1":1, "2":2, "3":3}
>>> a.items()

Find Same Keys

>>> a = {"1":1, "2":2, "3":3}
>>> b = {"2":2, "3":3, "4":4}
>>> [_ for _ in a.keys() if _ in b.keys()]
['3', '2']
>>> # better way
>>> c = set(a).intersection(set(b))
>>> list(c)
['3', '2']
>>> # or
>>> [_ for _ in a if _ in b]
['3', '2']
[('1', 1), ('3', 3), ('2', 2)]

Set a Default Value

>>> # intuitive but not recommend
>>> d = {}
>>> key = "foo"
>>> if key not in d:
...     d[key] = []
...

# using d.setdefault(key[, default])
>>> d = {}
>>> key = "foo"
>>> d.setdefault(key, [])
[]
>>> d[key] = 'bar'
>>> d
{'foo': 'bar'}

# using collections.defaultdict
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> d["key"]
[]
>>> d["foo"]
[]
>>> d["foo"].append("bar")
>>> d
defaultdict(<class 'list'>, {'key': [], 'foo': ['bar']})

dict.setdefault(key[, default]) returns its default value if key is not in the dictionary. However, if the key exists in the dictionary, the function will return its value.

>>> d = {}
>>> d.setdefault("key", [])
[]
>>> d["key"] = "bar"
>>> d.setdefault("key", [])
'bar'

Update Dictionary

>>> a = {"1":1, "2":2, "3":3}
>>> b = {"2":2, "3":3, "4":4}
>>> a.update(b)
>>> a
{'1': 1, '3': 3, '2': 2, '4': 4}

Merge Two Dictionaries

Python 3.4 or lower

>>> a = {"x": 55, "y": 66}
>>> b = {"a": "foo", "b": "bar"}
>>> c = a.copy()
>>> c.update(b)
>>> c
{'y': 66, 'x': 55, 'b': 'bar', 'a': 'foo'}

Python 3.5 or above

>>> a = {"x": 55, "y": 66}
>>> b = {"a": "foo", "b": "bar"}
>>> c = {**a, **b}
>>> c
{'x': 55, 'y': 66, 'a': 'foo', 'b': 'bar'}

Emulating a Dictionary

>>> class EmuDict(object):
...   def __init__(self, dict_):
...     self._dict = dict_
...   def __repr__(self):
...     return "EmuDict: " + repr(self._dict)
...   def __getitem__(self, key):
...     return self._dict[key]
...   def __setitem__(self, key, val):
...     self._dict[key] = val
...   def __delitem__(self, key):
...     del self._dict[key]
...   def __contains__(self, key):
...     return key in self._dict
...   def __iter__(self):
...     return iter(self._dict.keys())
...
>>> _ = {"1":1, "2":2, "3":3}
>>> emud = EmuDict(_)
>>> emud  # __repr__
EmuDict: {'1': 1, '2': 2, '3': 3}
>>> emud['1']  # __getitem__
1
>>> emud['5'] = 5  # __setitem__
>>> emud
EmuDict: {'1': 1, '2': 2, '3': 3, '5': 5}
>>> del emud['2']  # __delitem__
>>> emud
EmuDict: {'1': 1, '3': 3, '5': 5}
>>> for _ in emud:
...     print(emud[_], end=' ')  # __iter__
... else:
...     print()
...
1 3 5
>>> '1' in emud  # __contains__
True

LRU Cache

from collections import OrderedDict


class LRU(object):
        def __init__(self, maxsize=128):
                self._maxsize = maxsize
                self._cache = OrderedDict()

        def get(self, k):
                if k not in self._cache:
                        return None

                self._cache.move_to_end(k)
                return self._cache[k]

        def put(self, k, v):
                if k in self._cache:
                        self._cache.move_to_end(k)
                self._cache[k] = v
                if len(self._cache) > self._maxsize:
                        self._cache.popitem(last=False)

        def __str__(self):
                return str(self._cache)

        def __repr__(self):
                return self.__str__()

Note that dictionaries preserve insertion order from Python 3.7. Moreover, updating a key does not affect the order. Therefore, a dictionary can also simulate an LRU cache, which is similar to using an OrderedDict.

class LRU(object):
        def __init__(self, maxsize=128):
                self._maxsize = maxsize
                self._cache = {}

        def get(self, k):
                if k not in self._cache:
                        return None

                self.move_to_end(k)
                return self._cache[k]

        def put(self, k, v):
                if k in self._cache:
                        self.move_to_end(k)
                self._cache[k] = v
                if len(self._cache) > self._maxsize:
                        self.pop()

        def pop(self):
                it = iter(self._cache.keys())
                del self._cache[next(it)]

        def move_to_end(self, k):
                if k not in self._cache:
                        return
                v = self._cache[k]
                del self._cache[k]
                self._cache[k] = v

        def __str__(self):
                return str(self._cache)

        def __repr__(self):
                return self.__str__()