HashMap

See the original Rust documentation here.


patina.hashmap A hash map that wraps Python’s dict with Rust’s HashMap API.
HashMap(dct, V]] = None)
Entry(table, ~V][K, V], key) A view into a single entry into a map, which may either be vacant or occupied.
OccupiedEntry(table, ~V][K, V], key) A view into an occupied entry in a HashMap.
VacantEntry(table, ~V][K, V], key) A view into a vacant entry in HashMap.

A hash map that wraps Python’s dict with Rust’s HashMap API.

Examples

>>> from patina import HashMap
>>>
>>> book_reviews: HashMap[str, str] = HashMap()  # or HashMap.new()
>>>
>>> # Review some books.
>>> book_reviews.insert(
...     "Adventures of Huckleberry Finn",
...     "My favorite book.",
... )
None_
>>> book_reviews.insert(
...     "Grimms' Fairy Tales",
...     "Masterpiece.",
... )
None_
>>> book_reviews.insert(
...     "Pride and Prejudice",
...     "Very enjoyable.",
... )
None_
>>> book_reviews.insert(
...     "The Adventures of Sherlock Holmes",
...     "Eye lyked it alot.",
... )
None_
>>>
>>> # Check for a specific one.
>>> if not book_reviews.contains_key("Les Misérables"):
...     print(
...         "We've got {} reviews, but Les Misérables ain't one.".format(
...             len(book_reviews)
...         )
...     )
...
We've got 4 reviews, but Les Misérables ain't one.
>>>
>>> # oops, this review has a lot of spelling mistakes, let's deleted it.
>>> book_reviews.remove("The Adventures of Sherlock Holmes")
Some('Eye lyked it alot.')
>>>
>>> # Look up the values associated with some keys.
>>> to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]
>>> for book in to_find:
...     review = book_reviews.get(book)
...     if review.is_some():
...         print("{}: {}".format(book, review.unwrap()))
...     else:
...         print("{} is unreviewed.".format(book))
...
Pride and Prejudice: Very enjoyable.
Alice's Adventure in Wonderland is unreviewed.
>>>
>>> # Look up the value for a key (will raise KeyError if the key is not found).
>>> print("Review for Jane: {}".format(book_reviews["Pride and Prejudice"]))
Review for Jane: Very enjoyable.
>>>
>>> # Iterate over everything.
>>> for book, review in book_reviews:
...     print('{}: "{}"'.format(book, review))
...
Adventures of Huckleberry Finn: "My favorite book."
Grimms' Fairy Tales: "Masterpiece."
Pride and Prejudice: "Very enjoyable."

HashMap also implements an Entry API, which allows for more complex methods of getting, setting, updating, and removing keys and their values:

>>> from patina import HashMap
>>>
>>> player_stats = HashMap[str, int]()
>>>
>>> def random_stat_buff() -> int:
...     # could actually return some random value here - let's just return some
...     # fixed value for now
...     return 42
...
>>> # insert a key only if it doesn't exist
>>> player_stats.entry("health").or_insert(100)
Ref(100)
>>>
>>> # insert a key using a function that provides a new value only if it doesn't
>>> # already exist
>>> player_stats.entry("defence").or_insert_with(random_stat_buff)
Ref(42)
>>>
>>> # update a key, guarding against the key possibly not being set
>>> stat = player_stats.entry("attack").or_insert(100)
>>> stat.modify(lambda stat: stat + random_stat_buff())
Ref(142)

HashMap can be used with any key type that is Hashable.

>>> from dataclasses import dataclass
>>> from patina import HashMap
>>>
>>> @dataclass(frozen=True)  # frozen so dataclass will add a __hash__ impl
... class Viking:
...     name: str
...     country: str
...
>>> # Use a HashMap to store the vikings' health points.
>>> vikings = HashMap[Viking, int]()
>>>
>>> vikings.insert(Viking("Einar", "Norway"), 25)
None_
>>> vikings.insert(Viking("Olaf", "Denmark"), 24)
None_
>>> vikings.insert(Viking("Harald", "Iceland"), 12)
None_
>>>
>>> # Print the status of the vikings.
>>> for viking, health in vikings:
...     print(repr(viking), "has", health, "hp")
...
Viking(name='Einar', country='Norway') has 25 hp
Viking(name='Olaf', country='Denmark') has 24 hp
Viking(name='Harald', country='Iceland') has 12 hp

A HashMap with fixed list of elements can be initialized from a list:

>>> from patina import HashMap
>>>
>>> timber_resources = HashMap.from_iter(
...     [("Norway", 100), ("Denmark", 50), ("Iceland", 10)]
... )
>>> timber_resources
HashMap({'Norway': 100, 'Denmark': 50, 'Iceland': 10})

HashMap

class patina.hashmap.HashMap(dct: Optional[Dict[K, V]] = None)
__init__(dct: Optional[Dict[K, V]] = None)

Creates an empty HashMap.

>>> HashMap[str, int]()
HashMap({})
classmethod new()

Creates an empty HashMap.

>>> HashMap[str, int].new()
HashMap({})
keys() → Iterable[K]

An iterator visiting all keys in arbitrary order. The iterator element type is K.

>>> map = HashMap[str, int]()
>>> map.insert("a", 1)
None_
>>> map.insert("b", 2)
None_
>>> map.insert("c", 3)
None_
>>>
>>> for key in map.keys():
...     print(key)
...
a
b
c
values() → Iterable[V]

An iterator visiting all values in arbitrary order. The iterator element type is V.

>>> map = HashMap[str, int]()
>>> map.insert("a", 1)
None_
>>> map.insert("b", 2)
None_
>>> map.insert("c", 3)
None_
>>>
>>> for val in map.values():
...     print(val)
...
1
2
3
values_mut() → Iterable[patina.ref.Ref[~V][V]]

An iterator visiting all values mutably in arbitrary order. The iterator element type is Ref[V].

>>> map = HashMap[str, int]()
>>> map.insert("a", 1)
None_
>>> map.insert("b", 2)
None_
>>> map.insert("c", 3)
None_
>>>
>>> for val in map.values_mut():
...     val.modify(lambda v: v + 10)
...
Ref(11)
Ref(12)
Ref(13)
>>> for val in map.values():
...     print(val)
...
11
12
13
iter() → Iterable[Tuple[K, V]]

An iterator visiting all key-value pairs in arbitrary order. The iterator element type is Tuple[K, V].

Equivalent to iter(map).

>>> map = HashMap[str, int]()
>>> map.insert("a", 1)
None_
>>> map.insert("b", 2)
None_
>>> map.insert("c", 3)
None_
>>>
>>> for key, val in map.iter():
...     print("key:", key, "val:", val)
...
key: a val: 1
key: b val: 2
key: c val: 3
__iter__()

An iterator visiting all key-value pairs in arbitrary order. The iterator element type is Tuple[K, V].

>>> map = HashMap[str, int]()
>>> map.insert("a", 1)
None_
>>> map.insert("b", 2)
None_
>>> map.insert("c", 3)
None_
>>>
>>> for key, val in map:
...     print("key:", key, "val:", val)
...
key: a val: 1
key: b val: 2
key: c val: 3
iter_mut() → Iterable[Tuple[K, patina.ref.Ref[~V][V]]]

An iterator visiting all key-value pairs in arbitrary order, with mutable references to the values. The iterator element type is Tuple[K, Ref[V]].

>>> map = HashMap[str, int]()
>>> map.insert("a", 1)
None_
>>> map.insert("b", 2)
None_
>>> map.insert("c", 3)
None_
>>>
>>> for key, val in map.iter_mut():
...     val.modify(lambda v: v * 2)
...
Ref(2)
Ref(4)
Ref(6)
>>> for key, val in map:
...     print("key:", key, "val:", val)
...
key: a val: 2
key: b val: 4
key: c val: 6
len() → int

Returns the number of elements in the map.

Equivalent to len(map).

>>> a = HashMap[int, str]()
>>> a.len()
0
>>> a.insert(1, "a")
None_
>>> a.len()
1
__len__()

Returns the number of elements in the map.

>>> a = HashMap[int, str]()
>>> len(a)
0
>>> a.insert(1, "a")
None_
>>> len(a)
1
is_empty() → bool

Returns True if the map contains no elements.

>>> a = HashMap[int, str]()
>>> a.is_empty()
True
>>> a.insert(1, "a")
None_
>>> a.is_empty()
False
drain() → Iterable[Tuple[K, V]]

Clears the map, returning all key-value pairs as an iterator.

>>> from itertools import islice
>>>
>>> a = HashMap[int, str]()
>>> a.insert(1, "a")
None_
>>> a.insert(2, "b")
None_
>>>
>>> for k, v in islice(a.drain(), 1):
...     k == 1 or k == 2
...     v == "a" or v == "b"
...
True
True
>>> a.is_empty()
True
clear() → None

Clears the map, removing all key-value pairs.

>>> a = HashMap[int, str]()
>>> a.insert(1, "a")
None_
>>> a.clear()
>>> a.is_empty()
True
entry(key: K) → patina.hashmap.Entry[~K, ~V][K, V]

Gets the given key’s corresponding entry in the map for in-place manipulation.

>>> letters = HashMap[str, int]()
>>>
>>> for ch in "a short treatise on fungi":
...     counter = letters.entry(ch).or_insert(0)
...     _ = counter.modify(lambda i: i + 1)
...
>>> letters["s"]
2
>>> letters["t"]
3
>>> letters["u"]
1
>>> letters.get("y")
None_
get(key: K) → patina.option.Option[~V][V]

Returns a reference to the value corresponding to the keys.

>>> map = HashMap[int, str]()
>>> map.insert(1, "a")
None_
>>> map.get(1)
Some('a')
>>> map.get(2)
None_
get_key_value(key: K) → patina.option.Option[typing.Tuple[~K, ~V]][Tuple[K, V]]

Returns the key-value pair corresponding to the supplied key.

>>> map = HashMap[int, str]()
>>> map.insert(1, "a")
None_
>>> map.get_key_value(1)
Some((1, 'a'))
>>> map.get_key_value(2)
None_
__getitem__(key: K) → V

Returns a reference to the value corresponding to the supplied key.

Raises KeyError if the key is not present in the HashMap.

>>> map = HashMap[int, str]()
>>> map[123] = "abc"
>>> map[123]
'abc'
>>> map[234]
Traceback (most recent call last):
    ...
KeyError: 234
contains_key(key: K) → bool

Returns True if the map contains a value for the specified key.

>>> map = HashMap[int, str]()
>>> map.insert(1, "a")
None_
>>> map.contains_key(1)
True
>>> map.contains_key(2)
False
__contains__(key: K) → bool

Returns True if the map contains a value for the specified key.

>>> map = HashMap[int, str]()
>>> map.insert(1, "a")
None_
>>> 1 in map
True
>>> 2 in map
False
get_mut(key: K) → patina.option.Option[patina.ref.Ref[~V]][patina.ref.Ref[~V][V]]

Returns a mutable reference to the value corresponding to the key.

>>> map = HashMap[int, str]()
>>> map.insert(1, "a")
None_
>>> x = map.get_mut(1)
>>> if x.is_some():
...     x.unwrap().set("b")
...
>>> map[1]
'b'
insert(k: K, v: V) → patina.option.Option[~V][V]

Inserts a key-value pair into the map.

If the map did not have this key present, None_ is returned.

If the map did have this key present, the value is updated, and the old value is returned.

>>> map = HashMap[int, str]()
>>> map.insert(37, "a")
None_
>>> map.is_empty()
False
>>>
>>> map.insert(37, "b")
Some('a')
>>> map.insert(37, "c")
Some('b')
>>> map[37]
'c'
__setitem__(key: K, value: V) → None

Inserts a key-value pair into the map.

>>> map = HashMap[int, str]()
>>> map[37] = "a"
>>> map.is_empty()
False
>>>
>>> map[37] = "b"
>>> map[37] = "c"
>>> map[37]
'c'
remove(key: K) → patina.option.Option[~V][V]

Removes a key from the map, returning the value at the key if the key was previously in the map.

>>> map = HashMap[int, str]()
>>> map.insert(1, "a")
None_
>>> map.remove(1)
Some('a')
>>> map.remove(1)
None_
remove_entry(key: K) → patina.option.Option[typing.Tuple[~K, ~V]][Tuple[K, V]]

Removes a key from the map, returning the key and the value if the key was previously in the map.

>>> map = HashMap[int, str]()
>>> map.insert(1, "a")
None_
>>> map.remove_entry(1)
Some((1, 'a'))
>>> map.remove(1)
None_
__delitem__(key: K) → None

Removes a key from the map.

>>> map = HashMap[int, str]()
>>> map.insert(1, "a")
None_
>>> map.is_empty()
False
>>> del map[1]
>>> map.is_empty()
True
retain(f: Callable[[K, patina.ref.Ref[~V][V]], bool]) → None

Retains only the elements specified by the predicate.

In other words, remove all pairs (k, v) such that f(k, Ref(v)) returns False.

>>> map = HashMap.from_iter((x, x * 10) for x in range(8))
>>> map.retain(lambda k, _v: k % 2 == 0)
>>> len(map)
4
extend(it: Iterable[Tuple[K, V]]) → None

Extends a colluction with the contents of an iterator.

__eq__(other)

This method tests for self and other values to be equal, and is used by ==.

__weakref__

list of weak references to the object (if defined)

classmethod from_iter(it: Iterable[Tuple[K, V]]) → patina.hashmap.HashMap[~K, ~V][K, V]

Creates a value from an iterator.

class patina.hashmap.Entry(table: patina.hashmap.HashMap[~K, ~V][K, V], key: K)

A view into a single entry into a map, which may either be vacant or occupied.

This class is constructed from the entry() method on HashMap.

or_insert(default: V) → patina.ref.Ref[~V][V]

Ensures a value is in the entry by inserting the default if empty, and returns a mutable reference to the value in the entry.

>>> map = HashMap[str, int]()
>>> map.entry("poneyland").or_insert(3)
Ref(3)
>>> map["poneyland"]
3
>>> map.entry("poneyland").or_insert(10).modify(lambda v: v * 2)
Ref(6)
>>> map["poneyland"]
6
or_insert_with(default: Callable[[], V]) → patina.ref.Ref[~V][V]

Ensures a value is in the entry by inserting the result of the default function if empty, and returns a mutable reference to the value in the entry.

>>> map = HashMap[str, str]()
>>> s = "hoho"
>>> map.entry("poneyland").or_insert_with(lambda: s)
Ref('hoho')
>>> map["poneyland"]
'hoho'
or_insert_with_key(default: Callable[[K], V]) → patina.ref.Ref[~V][V]

Ensures a value is in the entry by inserting, if empty, the result of the default function. This method allows for generating key-derived values for insertion by providing the default function a reference to the key that was moved during the .entry(key) method call (not applicable to Python).

>>> map = HashMap[str, int]()
>>> map.entry("poneyland").or_insert_with_key(len)
Ref(9)
>>> map["poneyland"]
9
key() → K

Returns a reference to this entry’s key.

>>> map = HashMap[str, int]()
>>> map.entry("poneyland").key()
'poneyland'
and_modify(f: Callable[[patina.ref.Ref[~V][V]], None]) → patina.hashmap.Entry[~K, ~V][K, V]

Provides in-place mutable access to an occupied entry before any potential inserts into the map.

>>> from patina import Ref
>>>
>>> map = HashMap[str, int]()
>>>
>>> def add_one(ref: Ref[int]):
...     ref.modify(lambda val: val + 1)
...
>>>
>>> map.entry("poneyland") \
...     .and_modify(add_one) \
...     .or_insert(42)
Ref(42)
>>> map["poneyland"]
42
>>>
>>> map.entry("poneyland") \
...     .and_modify(add_one) \
...     .or_insert(42)
Ref(43)
>>> map["poneyland"]
43
class patina.hashmap.OccupiedEntry(table: patina.hashmap.HashMap[~K, ~V][K, V], key: K)

A view into an occupied entry in a HashMap. It is part of the Entry class hierarchy.

remove_entry() → Tuple[K, V]

Remove the entry from the map.

>>> map = HashMap[str, int]()
>>> map.entry("poneyland").or_insert(12)
Ref(12)
>>> o = map.entry("poneyland")
>>> if isinstance(o, OccupiedEntry):
...     o.remove_entry()
...
('poneyland', 12)
>>> "poneyland" in map
False
get() → V

Gets a reference to the value in the entry.

>>> map = HashMap[str, int]()
>>> map.entry("poneyland").or_insert(12)
Ref(12)
>>>
>>> o = map.entry("poneyland")
>>> if isinstance(o, OccupiedEntry):
...     print(o.get())
...
12
get_mut() → patina.ref.Ref[~V][V]

Gets a mutable reference to the value in the entry.

>>> map = HashMap[str, int]()
>>> map.entry("poneyland").or_insert(12)
Ref(12)
>>>
>>> map["poneyland"]
12
>>> o = map.entry("poneyland")
>>> if isinstance(o, OccupiedEntry):
...     o.get_mut().modify(lambda v: v + 10)
...     o.get_mut().modify(lambda v: v + 2)
...
Ref(22)
Ref(24)
>>> map["poneyland"]
24
insert(value: V) → V

Sets the value of the entry, and returns the entry’s old value.

>>> map = HashMap[str, int]()
>>> map.entry("poneyland").or_insert(12)
Ref(12)
>>>
>>> o = map.entry("poneyland")
>>> if isinstance(o, OccupiedEntry):
...     o.insert(15)
...
12
>>> map["poneyland"]
15
remove() → V

Takes the value out of the entry, and returns it.

>>> map = HashMap[str, int]()
>>> map.entry("poneyland").or_insert(12)
Ref(12)
>>>
>>> o = map.entry("poneyland")
>>> if isinstance(o, OccupiedEntry):
...     o.remove()
...
12
>>> "poneyland" in map
False
class patina.hashmap.VacantEntry(table: patina.hashmap.HashMap[~K, ~V][K, V], key: K)

A view into a vacant entry in HashMap. It is part of the Entry class hierarchy.

insert(value: V) → patina.ref.Ref[~V][V]

Sets the value of the entry with the VacantEntry’s key, and returns a mutable reference to it.

>>> map = HashMap[str, int]()
>>> o = map.entry("poneyland")
>>> if isinstance(o, VacantEntry):
...     o.insert(37)
...
Ref(37)
>>> map["poneyland"]
37