sain.collections.hash_map
An extended version of built-in dict but with extra functionality.
This contains Rust's std::collections::HashMap methods.
1# BSD 3-Clause License 2# 3# Copyright (c) 2022-Present, nxtlo 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 9# * Redistributions of source code must retain the above copyright notice, this 10# list of conditions and the following disclaimer. 11# 12# * Redistributions in binary form must reproduce the above copyright notice, 13# this list of conditions and the following disclaimer in the documentation 14# and/or other materials provided with the distribution. 15# 16# * Neither the name of the copyright holder nor the names of its 17# contributors may be used to endorse or promote products derived from 18# this software without specific prior written permission. 19# 20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30"""An extended version of built-in `dict` but with extra functionality. 31 32This contains Rust's `std::collections::HashMap` methods. 33""" 34 35from __future__ import annotations 36 37__all__ = ("HashMap", "RefMut") 38 39import collections.abc as collections 40import typing 41 42from sain import option as option 43from sain.convert import From 44from sain.convert import Into 45from sain.default import Default 46from sain.macros import rustc_diagnostic_item 47from sain.result import Err 48from sain.result import Ok 49 50from .base_iter import Drain 51from .base_iter import ExtractIf 52from .base_iter import Fn 53from .base_iter import IntoIterator 54from .base_iter import IntoKeys 55from .base_iter import IntoValues 56from .base_iter import Iter 57 58K = typing.TypeVar("K") 59V = typing.TypeVar("V") 60 61if typing.TYPE_CHECKING: 62 from typing_extensions import Never 63 from typing_extensions import Self 64 65 from sain.option import Option 66 from sain.result import Result 67 68 69class _RawMap( 70 typing.Generic[K, V], 71 collections.Mapping[K, V], 72 From[collections.Iterable[tuple[K, V]]], 73 Into[list[tuple[K, V]]], 74): 75 __slots__ = ("_source",) 76 77 def __init__(self, source: dict[K, V] | None = None, /) -> None: 78 self._source = source if source else {} 79 80 # constructors 81 82 @classmethod 83 def from_keys(cls, *iterable: tuple[K, V]) -> HashMap[K, V]: 84 """Create a new `HashMap` from a sequence of key-value pairs. 85 86 Example 87 ------- 88 ```py 89 tier_list = [ 90 ("S", "Top tier"), 91 ("A", "Very Good"), 92 ("B", "Good"), 93 ("C", "Average"), 94 ("D", "dodo") 95 ] 96 mapping = HashMap[str, str].from_keys(*tier_list) 97 ``` 98 """ 99 return HashMap({k: v for k, v in iterable}) 100 101 # trait impls 102 103 @classmethod 104 def from_value(cls, value: collections.Iterable[tuple[K, V]]) -> HashMap[K, V]: 105 """Creates a `HashMap` from an iterable of `(K, V)` key-value paris. 106 107 Same as `HashMap.from_keys(*iter)` 108 """ 109 return HashMap({k: v for k, v in value}) 110 111 def into(self) -> list[tuple[K, V]]: 112 """Turn this `HashMap` into a `[(K, V); len(self)]` key-value paris. 113 114 `self` is consumed afterwards. 115 116 Example 117 ------- 118 ```py 119 users = [(0, "user-0"), (1, "user-1")] 120 map1 = HashMap.from_keys(*users) 121 assert map1.into() == users 122 # map1 is dropped. 123 ``` 124 """ 125 return [(k, v) for k, v in self.leak().items()] 126 127 # default impls 128 129 def into_keys(self) -> IntoKeys[K]: 130 """Creates an iterator that consumes the map, yielding all of its keys. 131 132 `self` cannot be used after calling this. 133 134 Example 135 ------- 136 ```py 137 map1 = HashMap({ 138 "a": 1, 139 "b": 2, 140 "c": 3, 141 }) 142 keys = map1.into_keys().collect() 143 assert keys == ["a", "b", "c"] 144 ``` 145 """ 146 return IntoKeys(self.leak().keys()) 147 148 def into_values(self) -> IntoValues[V]: 149 """Creates an iterator that consumes the map, yielding all of its values. 150 151 `self` cannot be used after calling this. 152 153 Example 154 ------- 155 ```py 156 map1 = HashMap({ 157 "a": 1, 158 "b": 2, 159 "c": 3, 160 }) 161 values = map1.into_values().collect() 162 assert values == [1, 2, 3] 163 ``` 164 """ 165 return IntoValues(self.leak().values()) 166 167 def contains_key(self, k: K) -> bool: 168 """Check whether `k` is in `self` or not. 169 170 Example 171 ------- 172 ```py 173 users = HashMap({0: "user-0"}) 174 assert users.contains_key(0) is True 175 # similar to just doing 176 assert 0 in users 177 ``` 178 """ 179 return k in self 180 181 def is_empty(self) -> bool: 182 """Whether this `self` contains any items or not. 183 184 Example 185 ------- 186 ```py 187 storage: HashMap[str, None] = HashMap() 188 if storage.is_empty(): 189 ... 190 # Or just 191 if not storage: 192 ... 193 ``` 194 """ 195 return not self 196 197 def get(self, key: K) -> Option[V]: 198 """Get the value associated with `key`, returns `None` if not found. 199 200 Unlike `dict.get` which returns builtin `None`, This returns `Option[T]`. 201 202 Example 203 ------- 204 ```py 205 users: HashMap[str, int] = HashMap() 206 assert users.get("jack").is_none() 207 208 users = HashMap({"jack": None}) 209 assert users.get("jack").is_some() 210 ``` 211 """ 212 if key not in self: 213 return option.NOTHING 214 215 return option.Some(self._source[key]) 216 217 def get_with(self, f: collections.Callable[[], K]) -> Option[V]: 218 """Get the value associated with `key` returned from a callable `f()`, returns `None` if not found. 219 220 Example 221 ------- 222 ```py 223 def get_id() -> int: 224 return 0 225 226 map = HashMap({0: "buh", 1: "guh", 2: "luh"}) 227 assert map.get_with(get_id).unwrap() == "a" 228 ``` 229 """ 230 key = f() 231 if key not in self: 232 return option.NOTHING 233 234 return option.Some(self._source[key]) 235 236 def get_pairs(self, key: K) -> Option[tuple[K, V]]: 237 """Get both `key-value` pairs associated with `key`, returns `None` if not found. 238 239 Example 240 ------- 241 ```py 242 users: HashMap[str, int] = HashMap() 243 assert users.get_pairs("jack").is_none() 244 245 users = HashMap({"jack": 0}) 246 assert users.get("jack").unwrap() == ("jack", 0) 247 ``` 248 """ 249 if key not in self: 250 return option.NOTHING 251 252 return option.Some((key, self._source[key])) 253 254 def get_many(self, *keys: K) -> Option[collections.Collection[V]]: 255 """Attempts to get `len(keys)` values in the map at once. 256 257 Returns a collection of length `keys` with the results of each query. 258 None will be returned if any of the keys missing. 259 260 The time complexity is `O(N)`, where `N` is the length of `keys`. 261 262 Example 263 ------- 264 ```py 265 urls = HashMap({ 266 "google": "www.google.com", 267 "github": "www.github.com", 268 "facebook": "www.facebook.com", 269 "twitter": "www.twitter.com", 270 }) 271 assert urls.get_many("google","github").unwrap() == ["www.google.com", "www.github.com"] 272 273 # missing keys results in `None` 274 assert urls.get_many("google", "linkedin").is_none() 275 # duplicate keys results in `None` 276 assert urls.get_many("google", "google").is_none() 277 ``` 278 """ 279 if not self._source: 280 return option.NOTHING 281 282 seen: set[K] = set() 283 result: list[V] = [] 284 285 for key in keys: 286 if key not in self._source or key in seen: 287 return option.NOTHING 288 289 seen.add(key) 290 result.append(self._source[key]) 291 292 return option.Some(result) 293 294 def iter(self) -> Iter[tuple[K, V]]: 295 """Creates an iterator over the key-value pairs of the map. 296 297 Example 298 ------- 299 ```py 300 map = HashMap.from_keys([ 301 ("a", 1), 302 ("b", 2), 303 ]) 304 for k, v in map.iter(): 305 print(f"{k=}: {v=}") 306 ``` 307 """ 308 return Iter(self._source.items()) 309 310 def into_iter(self) -> IntoIterator[K, V]: 311 """Creates a consuming iterator, that is, one that moves each key-value pair out of the map. 312 The map cannot be used after calling this. 313 314 Example 315 ------- 316 ```py 317 map = HashMap.from_keys([ 318 ("a", 1), 319 ("b", 2), 320 ("c", 3), 321 ]) 322 for k, v in map.into_iter(): 323 print(f"{k=}: {v=}") 324 ``` 325 """ 326 return IntoIterator(self.leak()) 327 328 def len(self) -> int: 329 """Get how many elements are in this map. 330 331 Example 332 ------- 333 ```py 334 map: HashMap[str, int] = HashMap() 335 assert map.len() == 0 336 ``` 337 """ 338 return len(self._source) 339 340 # conversions 341 342 def leak(self) -> collections.MutableMapping[K, V]: 343 """Leaks and returns a mutable reference to the underlying map. 344 345 `self` becomes unusable after calling this. 346 347 Example 348 ------- 349 ```py 350 map = HashMap({0: 1}) 351 inner = map.leak() 352 assert inner == {0: 1} 353 ``` 354 """ 355 out = self._source 356 del self._source 357 return out 358 359 # built-ins 360 361 def copy(self) -> Self: 362 """Copy the contents of this hash map into a new one. 363 364 Example 365 ------- 366 ```py 367 hashmap: HashMap[str, None] = HashMap({'1': None, '2': None}) 368 copy = hashmap.copy() 369 assert hashmap == copy 370 ``` 371 """ 372 return self.__class__(self._source.copy()) 373 374 def __repr__(self) -> str: 375 return self._source.__repr__() 376 377 def __iter__(self) -> collections.Iterator[K]: 378 return self._source.__iter__() 379 380 def __len__(self) -> int: 381 return self._source.__len__() 382 383 def __getitem__(self, key: K, /) -> V: 384 return self._source[key] 385 386 def __setitem__(self, _key: Never, _value: Never) -> Never: 387 raise NotImplementedError( 388 "`HashMap` is immutable, use `.as_mut()` to make it mutable instead" 389 ) 390 391 def __delitem__(self, _key: Never) -> Never: 392 raise NotImplementedError( 393 "`HashMap` is immutable, use `.as_mut()` to make it mutable instead" 394 ) 395 396 397@rustc_diagnostic_item("HashMap") 398class HashMap(_RawMap[K, V], Default["HashMap[K, V]"]): 399 """An immutable key-value dictionary. 400 401 But default, `HashMap` is immutable, it cannot change its values after initializing it. however, 402 you can return a mutable reference to this hashmap via `HashMap.as_mut` method, it returns a reference to the underlying map. 403 404 Example 405 ------- 406 ```py 407 # initialize it with a source. after that, item insertion is not allowed. 408 books: HashMap[str, str] = HashMap({ 409 "Adventures of Huckleberry Finn": "My favorite book." 410 }) 411 # get a mutable reference to it to be able to. 412 books_mut = books.as_mut() 413 # You can either call `.insert`, which is similar to Rust's. 414 books_mut.insert( 415 "Grimms Fairy Tales", 416 "Masterpiece.", 417 ) 418 # Or via item assignments 419 books_mut["Pride and Prejudice"] = "Very enjoyable." 420 print(books) 421 422 for book, review in books.items(): 423 print(book, review) 424 ``` 425 426 Parameters 427 ---------- 428 source: `dict[K, V]` 429 A dictionary to point to. this will be used as the underlying source. 430 """ 431 432 __slots__ = ("_source",) 433 434 def __init__(self, source: dict[K, V] | None = None, /) -> None: 435 super().__init__(source) 436 437 @staticmethod 438 def default() -> HashMap[K, V]: 439 """Creates an empty `HashMap<K, V>`.""" 440 return HashMap() 441 442 @classmethod 443 def from_mut(cls, source: dict[K, V] | None = None, /) -> RefMut[K, V]: 444 """Create a new mutable `HashMap`, with the given source if available. 445 446 Example 447 ------- 448 ```py 449 books = HashMap.from_mut() 450 books[0] = "Twilight" 451 ``` 452 """ 453 return RefMut(source or {}) 454 455 @staticmethod 456 def from_keys_mut(*iterable: tuple[K, V]) -> RefMut[K, V]: 457 """Create a new mutable `HashMap` from a sequence of key-value pairs. 458 459 Example 460 ------- 461 ```py 462 tier_list = [ 463 ("S", "Top tier"), 464 ("A", "Very Good"), 465 ("B", "Good"), 466 ("C", "Average"), 467 ("D", "dodo") 468 ] 469 mapping: RefMut[str, str] = HashMap.from_keys_mut(*tier_list) 470 ``` 471 """ 472 return RefMut({k: v for k, v in iterable}) 473 474 def as_mut(self) -> RefMut[K, V]: 475 """Get a mutable reference to this hash map. 476 477 Example 478 ------- 479 ```py 480 map: HashMap[str, float] = HashMap() 481 482 # Get a reference to map 483 mut = map.as_mut() 484 mut.insert("sqrt", 1.0) 485 del mut # not needed anymore 486 487 assert map == {"sqrt": 1.0} 488 ``` 489 """ 490 return RefMut(self._source) 491 492 493@typing.final 494class RefMut(_RawMap[K, V], collections.MutableMapping[K, V], Default["RefMut[K, V]"]): 495 """A reference to a mutable dictionary / hashmap. 496 497 Ideally, you want to use `HashMap.as_mut()` / `HashMap.from_mut` methods to create this. 498 """ 499 500 __slots__ = ("_source",) 501 502 def __init__(self, source: dict[K, V], /) -> None: 503 super().__init__(source) 504 self._source = source 505 506 @staticmethod 507 def default() -> RefMut[K, V]: 508 """Creates a new, mutable, empty `RefMut<K, V>`.""" 509 return RefMut({}) 510 511 def insert(self, key: K, value: V) -> Option[V]: 512 """Insert a key/value pair into the map. 513 514 if `key` is not present in the map, `None` is returned. otherwise, the value is updated, and the old value 515 is returned. 516 517 Example 518 ------- 519 ```py 520 users = HashMap.from_mut({0: "admin"}) 521 assert users.insert(1, "admin").is_none() 522 old = users.insert(0, "normal").unwrap() 523 assert old == "admin" 524 ``` 525 """ 526 if key not in self: 527 self[key] = value 528 return option.NOTHING 529 530 old = self[key] 531 self[key] = value 532 return option.Some(old) 533 534 def try_insert(self, key: K, value: V) -> Result[V, K]: 535 """Tries to insert `key` and `value` into the map, returning `Err(key)` if `key` is already present. 536 537 Example 538 ------- 539 ```py 540 users = HashMap.from_mut({0: "admin"}) 541 assert users.try_insert(1, "claudia").is_ok() 542 assert users.try_insert(0, "doppler").is_err() 543 ``` 544 """ 545 if key in self: 546 return Err(key) 547 548 self[key] = value 549 return Ok(value) 550 551 def remove(self, key: K) -> Option[V]: 552 """Remove a key from the map, returning the value of the key if it was previously in the map. 553 554 Example 555 ------- 556 ```py 557 map = HashMap.from_mut() 558 map.insert(0, "a") 559 map.remove(0).unwrap() == "a" 560 map.remove(0).is_none() 561 ``` 562 """ 563 if key not in self: 564 return option.NOTHING 565 566 v = self[key] 567 del self[key] 568 return option.Some(v) 569 570 def remove_entry(self, key: K) -> Option[tuple[K, V]]: 571 """Remove a key from the map, returning the key and value if it was previously in the map. 572 573 Example 574 ------- 575 ```py 576 map = HashMap.from_mut() 577 map[0] = "a" 578 assert map.remove_entry(0).unwrap() == (0, "a") 579 assert map.remove_entry(0).is_none() 580 ``` 581 """ 582 if key not in self: 583 return option.NOTHING 584 585 v = self[key] 586 del self[key] 587 return option.Some((key, v)) 588 589 def retain(self, f: collections.Callable[[K, V], bool]) -> None: 590 """Remove items from this map based on `f(key, value)` returning `False`. 591 592 Example 593 ------- 594 ```py 595 users = HashMap.from_mut({ 596 "user1": "admin", 597 "user2": "admin", 598 "user3": "regular", 599 "jack": "admin" 600 }) 601 users.retain( 602 lambda user, role: role == "admin" and 603 user.startswith("user") 604 ) 605 for user, role in users.items(): 606 print(user, role) 607 608 # user1 admin 609 # user2 admin 610 """ 611 for k, v in self._source.copy().items(): 612 if not f(k, v): 613 del self[k] 614 615 def drain(self) -> Drain[K, V]: 616 """Clears the map, returning all key-value pairs as an iterator. Keeps the hashmap for reuse. 617 618 Example 619 ------- 620 ```py 621 map = HashMap.from_mut() 622 map.insert(0, "a") 623 map.drain().collect() == [(0, "a")] 624 assert map.is_empty() 625 ``` 626 """ 627 return Drain(self._source) 628 629 def extract_if(self, pred: Fn[K, V]) -> ExtractIf[K, V]: 630 """Creates an iterator which uses a closure to determine if an element should be removed. 631 632 If the closure returns true, the element is removed from the map and yielded. If the closure returns false, 633 the element remains in the map and will not be yielded. 634 635 If you don't need at iterator, use `retain` instead. 636 637 Example 638 ------- 639 ```py 640 odds = HashMap.from_mut({0: 0, 1: 1, 2: 2, 3: 3, 4: 4}) 641 evens = odds.extract_if(lambda k, _v: k % 2 == 0).collect() 642 assert odds == {1: 1, 3: 3} 643 assert evens == [(0, 0), (2, 2), (4, 4)] 644 ``` 645 """ 646 return ExtractIf(self._source, pred) 647 648 def __repr__(self) -> str: 649 return self._source.__repr__() 650 651 def __setitem__(self, key: K, value: V, /) -> None: 652 self._source[key] = value 653 654 def __delitem__(self, key: K, /) -> None: 655 del self._source[key] 656 657 def __iter__(self) -> collections.Iterator[K]: 658 return self._source.__iter__() 659 660 def __len__(self) -> int: 661 return self._source.__len__()
398@rustc_diagnostic_item("HashMap") 399class HashMap(_RawMap[K, V], Default["HashMap[K, V]"]): 400 """An immutable key-value dictionary. 401 402 But default, `HashMap` is immutable, it cannot change its values after initializing it. however, 403 you can return a mutable reference to this hashmap via `HashMap.as_mut` method, it returns a reference to the underlying map. 404 405 Example 406 ------- 407 ```py 408 # initialize it with a source. after that, item insertion is not allowed. 409 books: HashMap[str, str] = HashMap({ 410 "Adventures of Huckleberry Finn": "My favorite book." 411 }) 412 # get a mutable reference to it to be able to. 413 books_mut = books.as_mut() 414 # You can either call `.insert`, which is similar to Rust's. 415 books_mut.insert( 416 "Grimms Fairy Tales", 417 "Masterpiece.", 418 ) 419 # Or via item assignments 420 books_mut["Pride and Prejudice"] = "Very enjoyable." 421 print(books) 422 423 for book, review in books.items(): 424 print(book, review) 425 ``` 426 427 Parameters 428 ---------- 429 source: `dict[K, V]` 430 A dictionary to point to. this will be used as the underlying source. 431 """ 432 433 __slots__ = ("_source",) 434 435 def __init__(self, source: dict[K, V] | None = None, /) -> None: 436 super().__init__(source) 437 438 @staticmethod 439 def default() -> HashMap[K, V]: 440 """Creates an empty `HashMap<K, V>`.""" 441 return HashMap() 442 443 @classmethod 444 def from_mut(cls, source: dict[K, V] | None = None, /) -> RefMut[K, V]: 445 """Create a new mutable `HashMap`, with the given source if available. 446 447 Example 448 ------- 449 ```py 450 books = HashMap.from_mut() 451 books[0] = "Twilight" 452 ``` 453 """ 454 return RefMut(source or {}) 455 456 @staticmethod 457 def from_keys_mut(*iterable: tuple[K, V]) -> RefMut[K, V]: 458 """Create a new mutable `HashMap` from a sequence of key-value pairs. 459 460 Example 461 ------- 462 ```py 463 tier_list = [ 464 ("S", "Top tier"), 465 ("A", "Very Good"), 466 ("B", "Good"), 467 ("C", "Average"), 468 ("D", "dodo") 469 ] 470 mapping: RefMut[str, str] = HashMap.from_keys_mut(*tier_list) 471 ``` 472 """ 473 return RefMut({k: v for k, v in iterable}) 474 475 def as_mut(self) -> RefMut[K, V]: 476 """Get a mutable reference to this hash map. 477 478 Example 479 ------- 480 ```py 481 map: HashMap[str, float] = HashMap() 482 483 # Get a reference to map 484 mut = map.as_mut() 485 mut.insert("sqrt", 1.0) 486 del mut # not needed anymore 487 488 assert map == {"sqrt": 1.0} 489 ``` 490 """ 491 return RefMut(self._source)
An immutable key-value dictionary.
But default, HashMap is immutable, it cannot change its values after initializing it. however,
you can return a mutable reference to this hashmap via HashMap.as_mut method, it returns a reference to the underlying map.
Example
# initialize it with a source. after that, item insertion is not allowed.
books: HashMap[str, str] = HashMap({
"Adventures of Huckleberry Finn": "My favorite book."
})
# get a mutable reference to it to be able to.
books_mut = books.as_mut()
# You can either call `.insert`, which is similar to Rust's.
books_mut.insert(
"Grimms Fairy Tales",
"Masterpiece.",
)
# Or via item assignments
books_mut["Pride and Prejudice"] = "Very enjoyable."
print(books)
for book, review in books.items():
print(book, review)
Parameters
- source (
dict[K, V]): A dictionary to point to. this will be used as the underlying source. - # Implementations
- **This class implements HashMap:
438 @staticmethod 439 def default() -> HashMap[K, V]: 440 """Creates an empty `HashMap<K, V>`.""" 441 return HashMap()
Creates an empty HashMap<K, V>.
443 @classmethod 444 def from_mut(cls, source: dict[K, V] | None = None, /) -> RefMut[K, V]: 445 """Create a new mutable `HashMap`, with the given source if available. 446 447 Example 448 ------- 449 ```py 450 books = HashMap.from_mut() 451 books[0] = "Twilight" 452 ``` 453 """ 454 return RefMut(source or {})
Create a new mutable HashMap, with the given source if available.
Example
books = HashMap.from_mut()
books[0] = "Twilight"
456 @staticmethod 457 def from_keys_mut(*iterable: tuple[K, V]) -> RefMut[K, V]: 458 """Create a new mutable `HashMap` from a sequence of key-value pairs. 459 460 Example 461 ------- 462 ```py 463 tier_list = [ 464 ("S", "Top tier"), 465 ("A", "Very Good"), 466 ("B", "Good"), 467 ("C", "Average"), 468 ("D", "dodo") 469 ] 470 mapping: RefMut[str, str] = HashMap.from_keys_mut(*tier_list) 471 ``` 472 """ 473 return RefMut({k: v for k, v in iterable})
Create a new mutable HashMap from a sequence of key-value pairs.
Example
tier_list = [
("S", "Top tier"),
("A", "Very Good"),
("B", "Good"),
("C", "Average"),
("D", "dodo")
]
mapping: RefMut[str, str] = HashMap.from_keys_mut(*tier_list)
475 def as_mut(self) -> RefMut[K, V]: 476 """Get a mutable reference to this hash map. 477 478 Example 479 ------- 480 ```py 481 map: HashMap[str, float] = HashMap() 482 483 # Get a reference to map 484 mut = map.as_mut() 485 mut.insert("sqrt", 1.0) 486 del mut # not needed anymore 487 488 assert map == {"sqrt": 1.0} 489 ``` 490 """ 491 return RefMut(self._source)
Get a mutable reference to this hash map.
Example
map: HashMap[str, float] = HashMap()
# Get a reference to map
mut = map.as_mut()
mut.insert("sqrt", 1.0)
del mut # not needed anymore
assert map == {"sqrt": 1.0}
494@typing.final 495class RefMut(_RawMap[K, V], collections.MutableMapping[K, V], Default["RefMut[K, V]"]): 496 """A reference to a mutable dictionary / hashmap. 497 498 Ideally, you want to use `HashMap.as_mut()` / `HashMap.from_mut` methods to create this. 499 """ 500 501 __slots__ = ("_source",) 502 503 def __init__(self, source: dict[K, V], /) -> None: 504 super().__init__(source) 505 self._source = source 506 507 @staticmethod 508 def default() -> RefMut[K, V]: 509 """Creates a new, mutable, empty `RefMut<K, V>`.""" 510 return RefMut({}) 511 512 def insert(self, key: K, value: V) -> Option[V]: 513 """Insert a key/value pair into the map. 514 515 if `key` is not present in the map, `None` is returned. otherwise, the value is updated, and the old value 516 is returned. 517 518 Example 519 ------- 520 ```py 521 users = HashMap.from_mut({0: "admin"}) 522 assert users.insert(1, "admin").is_none() 523 old = users.insert(0, "normal").unwrap() 524 assert old == "admin" 525 ``` 526 """ 527 if key not in self: 528 self[key] = value 529 return option.NOTHING 530 531 old = self[key] 532 self[key] = value 533 return option.Some(old) 534 535 def try_insert(self, key: K, value: V) -> Result[V, K]: 536 """Tries to insert `key` and `value` into the map, returning `Err(key)` if `key` is already present. 537 538 Example 539 ------- 540 ```py 541 users = HashMap.from_mut({0: "admin"}) 542 assert users.try_insert(1, "claudia").is_ok() 543 assert users.try_insert(0, "doppler").is_err() 544 ``` 545 """ 546 if key in self: 547 return Err(key) 548 549 self[key] = value 550 return Ok(value) 551 552 def remove(self, key: K) -> Option[V]: 553 """Remove a key from the map, returning the value of the key if it was previously in the map. 554 555 Example 556 ------- 557 ```py 558 map = HashMap.from_mut() 559 map.insert(0, "a") 560 map.remove(0).unwrap() == "a" 561 map.remove(0).is_none() 562 ``` 563 """ 564 if key not in self: 565 return option.NOTHING 566 567 v = self[key] 568 del self[key] 569 return option.Some(v) 570 571 def remove_entry(self, key: K) -> Option[tuple[K, V]]: 572 """Remove a key from the map, returning the key and value if it was previously in the map. 573 574 Example 575 ------- 576 ```py 577 map = HashMap.from_mut() 578 map[0] = "a" 579 assert map.remove_entry(0).unwrap() == (0, "a") 580 assert map.remove_entry(0).is_none() 581 ``` 582 """ 583 if key not in self: 584 return option.NOTHING 585 586 v = self[key] 587 del self[key] 588 return option.Some((key, v)) 589 590 def retain(self, f: collections.Callable[[K, V], bool]) -> None: 591 """Remove items from this map based on `f(key, value)` returning `False`. 592 593 Example 594 ------- 595 ```py 596 users = HashMap.from_mut({ 597 "user1": "admin", 598 "user2": "admin", 599 "user3": "regular", 600 "jack": "admin" 601 }) 602 users.retain( 603 lambda user, role: role == "admin" and 604 user.startswith("user") 605 ) 606 for user, role in users.items(): 607 print(user, role) 608 609 # user1 admin 610 # user2 admin 611 """ 612 for k, v in self._source.copy().items(): 613 if not f(k, v): 614 del self[k] 615 616 def drain(self) -> Drain[K, V]: 617 """Clears the map, returning all key-value pairs as an iterator. Keeps the hashmap for reuse. 618 619 Example 620 ------- 621 ```py 622 map = HashMap.from_mut() 623 map.insert(0, "a") 624 map.drain().collect() == [(0, "a")] 625 assert map.is_empty() 626 ``` 627 """ 628 return Drain(self._source) 629 630 def extract_if(self, pred: Fn[K, V]) -> ExtractIf[K, V]: 631 """Creates an iterator which uses a closure to determine if an element should be removed. 632 633 If the closure returns true, the element is removed from the map and yielded. If the closure returns false, 634 the element remains in the map and will not be yielded. 635 636 If you don't need at iterator, use `retain` instead. 637 638 Example 639 ------- 640 ```py 641 odds = HashMap.from_mut({0: 0, 1: 1, 2: 2, 3: 3, 4: 4}) 642 evens = odds.extract_if(lambda k, _v: k % 2 == 0).collect() 643 assert odds == {1: 1, 3: 3} 644 assert evens == [(0, 0), (2, 2), (4, 4)] 645 ``` 646 """ 647 return ExtractIf(self._source, pred) 648 649 def __repr__(self) -> str: 650 return self._source.__repr__() 651 652 def __setitem__(self, key: K, value: V, /) -> None: 653 self._source[key] = value 654 655 def __delitem__(self, key: K, /) -> None: 656 del self._source[key] 657 658 def __iter__(self) -> collections.Iterator[K]: 659 return self._source.__iter__() 660 661 def __len__(self) -> int: 662 return self._source.__len__()
A reference to a mutable dictionary / hashmap.
Ideally, you want to use HashMap.as_mut() / HashMap.from_mut methods to create this.
507 @staticmethod 508 def default() -> RefMut[K, V]: 509 """Creates a new, mutable, empty `RefMut<K, V>`.""" 510 return RefMut({})
Creates a new, mutable, empty RefMut<K, V>.
512 def insert(self, key: K, value: V) -> Option[V]: 513 """Insert a key/value pair into the map. 514 515 if `key` is not present in the map, `None` is returned. otherwise, the value is updated, and the old value 516 is returned. 517 518 Example 519 ------- 520 ```py 521 users = HashMap.from_mut({0: "admin"}) 522 assert users.insert(1, "admin").is_none() 523 old = users.insert(0, "normal").unwrap() 524 assert old == "admin" 525 ``` 526 """ 527 if key not in self: 528 self[key] = value 529 return option.NOTHING 530 531 old = self[key] 532 self[key] = value 533 return option.Some(old)
Insert a key/value pair into the map.
if key is not present in the map, None is returned. otherwise, the value is updated, and the old value
is returned.
Example
users = HashMap.from_mut({0: "admin"})
assert users.insert(1, "admin").is_none()
old = users.insert(0, "normal").unwrap()
assert old == "admin"
535 def try_insert(self, key: K, value: V) -> Result[V, K]: 536 """Tries to insert `key` and `value` into the map, returning `Err(key)` if `key` is already present. 537 538 Example 539 ------- 540 ```py 541 users = HashMap.from_mut({0: "admin"}) 542 assert users.try_insert(1, "claudia").is_ok() 543 assert users.try_insert(0, "doppler").is_err() 544 ``` 545 """ 546 if key in self: 547 return Err(key) 548 549 self[key] = value 550 return Ok(value)
Tries to insert key and value into the map, returning Err(key) if key is already present.
Example
users = HashMap.from_mut({0: "admin"})
assert users.try_insert(1, "claudia").is_ok()
assert users.try_insert(0, "doppler").is_err()
552 def remove(self, key: K) -> Option[V]: 553 """Remove a key from the map, returning the value of the key if it was previously in the map. 554 555 Example 556 ------- 557 ```py 558 map = HashMap.from_mut() 559 map.insert(0, "a") 560 map.remove(0).unwrap() == "a" 561 map.remove(0).is_none() 562 ``` 563 """ 564 if key not in self: 565 return option.NOTHING 566 567 v = self[key] 568 del self[key] 569 return option.Some(v)
Remove a key from the map, returning the value of the key if it was previously in the map.
Example
map = HashMap.from_mut()
map.insert(0, "a")
map.remove(0).unwrap() == "a"
map.remove(0).is_none()
571 def remove_entry(self, key: K) -> Option[tuple[K, V]]: 572 """Remove a key from the map, returning the key and value if it was previously in the map. 573 574 Example 575 ------- 576 ```py 577 map = HashMap.from_mut() 578 map[0] = "a" 579 assert map.remove_entry(0).unwrap() == (0, "a") 580 assert map.remove_entry(0).is_none() 581 ``` 582 """ 583 if key not in self: 584 return option.NOTHING 585 586 v = self[key] 587 del self[key] 588 return option.Some((key, v))
Remove a key from the map, returning the key and value if it was previously in the map.
Example
map = HashMap.from_mut()
map[0] = "a"
assert map.remove_entry(0).unwrap() == (0, "a")
assert map.remove_entry(0).is_none()
590 def retain(self, f: collections.Callable[[K, V], bool]) -> None: 591 """Remove items from this map based on `f(key, value)` returning `False`. 592 593 Example 594 ------- 595 ```py 596 users = HashMap.from_mut({ 597 "user1": "admin", 598 "user2": "admin", 599 "user3": "regular", 600 "jack": "admin" 601 }) 602 users.retain( 603 lambda user, role: role == "admin" and 604 user.startswith("user") 605 ) 606 for user, role in users.items(): 607 print(user, role) 608 609 # user1 admin 610 # user2 admin 611 """ 612 for k, v in self._source.copy().items(): 613 if not f(k, v): 614 del self[k]
Remove items from this map based on f(key, value) returning False.
Example
```py users = HashMap.from_mut({ "user1": "admin", "user2": "admin", "user3": "regular", "jack": "admin" }) users.retain( lambda user, role: role == "admin" and user.startswith("user") ) for user, role in users.items(): print(user, role)
user1 admin
user2 admin
616 def drain(self) -> Drain[K, V]: 617 """Clears the map, returning all key-value pairs as an iterator. Keeps the hashmap for reuse. 618 619 Example 620 ------- 621 ```py 622 map = HashMap.from_mut() 623 map.insert(0, "a") 624 map.drain().collect() == [(0, "a")] 625 assert map.is_empty() 626 ``` 627 """ 628 return Drain(self._source)
Clears the map, returning all key-value pairs as an iterator. Keeps the hashmap for reuse.
Example
map = HashMap.from_mut()
map.insert(0, "a")
map.drain().collect() == [(0, "a")]
assert map.is_empty()
630 def extract_if(self, pred: Fn[K, V]) -> ExtractIf[K, V]: 631 """Creates an iterator which uses a closure to determine if an element should be removed. 632 633 If the closure returns true, the element is removed from the map and yielded. If the closure returns false, 634 the element remains in the map and will not be yielded. 635 636 If you don't need at iterator, use `retain` instead. 637 638 Example 639 ------- 640 ```py 641 odds = HashMap.from_mut({0: 0, 1: 1, 2: 2, 3: 3, 4: 4}) 642 evens = odds.extract_if(lambda k, _v: k % 2 == 0).collect() 643 assert odds == {1: 1, 3: 3} 644 assert evens == [(0, 0), (2, 2), (4, 4)] 645 ``` 646 """ 647 return ExtractIf(self._source, pred)
Creates an iterator which uses a closure to determine if an element should be removed.
If the closure returns true, the element is removed from the map and yielded. If the closure returns false, the element remains in the map and will not be yielded.
If you don't need at iterator, use retain instead.
Example
odds = HashMap.from_mut({0: 0, 1: 1, 2: 2, 3: 3, 4: 4})
evens = odds.extract_if(lambda k, _v: k % 2 == 0).collect()
assert odds == {1: 1, 3: 3}
assert evens == [(0, 0), (2, 2), (4, 4)]