stl_treemap.tree_multimap
Ordered multimap backed by a red-black tree.
1"""Ordered multimap backed by a red-black tree.""" 2 3from __future__ import annotations 4 5from collections import UserDict 6from collections.abc import Callable, Collection, Iterable 7from typing import Any 8 9from stl_treemap.insertion_result import InsertionResult 10from stl_treemap.iterators import ReverseIterator, TreeIterator 11from stl_treemap.policies import KeyValuePolicy 12from stl_treemap.py_iterators import PyIterator, PyReverseIterator 13from stl_treemap.tree import Tree 14from stl_treemap.tree_node import TreeNode 15 16 17class TreeMultiMap[K, V](Collection[K]): 18 """ 19 Ordered map allowing multiple entries with the same key, backed by a red-black tree. 20 21 Unlike TreeMap, duplicate keys are permitted. Entries with equal keys appear 22 in insertion order and are kept in their key's sorted position relative to 23 entries with different keys. Lookup, insertion, and deletion are all O(log n). 24 25 Example:: 26 27 m = TreeMultiMap() 28 m[2] = "b1" 29 m[2] = "b2" 30 m[1] = "a" 31 for key, value in m: 32 print(f"{key}: {value}") 33 # 1: a 34 # 2: b1 35 # 2: b2 36 """ 37 38 def __init__(self, iterable: Iterable[tuple[K, V]] | None = None, **kwargs) -> None: 39 """ 40 Create an empty multimap, or pre-populate it from an iterable of (key, value) pairs. 41 42 Each pair in *iterable* is inserted independently; duplicate keys are kept. 43 44 Args: 45 iterable: Optional iterable of (key, value) tuples. 46 kwargs: Another way to provide key-value pairs. 47 48 Raises: 49 TypeError: When *iterable* is not iterable. 50 51 Example:: 52 53 m = TreeMultiMap() 54 m = TreeMultiMap([[2, "B"], [1, "A"], [2, "B2"]]) 55 m = TreeMultiMap({2: "B", 1: "A", 3: "C"}) 56 m = TreeMultiMap(A=1, B=2) # {"A": 1, "B": 2} 57 58 """ 59 self._t: Tree[K, V] = Tree() 60 self._t.value_policy = KeyValuePolicy() 61 if iterable is not None: 62 self.update(iterable) 63 if kwargs: 64 self.update(kwargs.items()) 65 66 def update(self, iterable: Iterable[tuple[K, V]]) -> None: 67 """ 68 Add all contents from the iterable of (key, value) pairs. 69 70 Args: 71 iterable: Optional iterable of (key, value) tuples. 72 73 Raises: 74 TypeError: When *iterable* is not iterable. 75 76 Example:: 77 78 TreeMultiMap().update(TreeMultiMap({2: "B", 1: "A", 3: "C"})) 79 TreeMultiMap().update({2: "B", 1: "A", 3: "C"}) 80 TreeMultiMap().update({2: "B", 1: "A", 3: "C"}.items()) 81 TreeMultiMap().update([[2, "B"], [1, "A"], [3, "C"]]) 82 83 """ 84 if isinstance(iterable, (dict, UserDict, TreeMultiMap)): 85 for k, v in iterable.items(): 86 self.set(k, v) 87 elif hasattr(iterable, "__iter__"): 88 for k, v in iterable: 89 self.set(k, v) 90 else: 91 raise TypeError("TreeMultiMap accepts only iterable objects") 92 93 # ------------------------------------------------------------------ 94 # Python dict-compatible methods 95 # ------------------------------------------------------------------ 96 97 def clear(self) -> None: 98 """ 99 Remove all key-value pairs. 100 101 Example:: 102 103 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 104 m.clear() 105 len(m) # 0 106 107 """ 108 self._t.clear() 109 110 def delete(self, key: K) -> None: 111 """ 112 @private Remove the first entry with *key*; does nothing if the key is absent. 113 114 When multiple entries share the same key, only the first one is removed. 115 Call repeatedly or use erase() to remove all of them. 116 117 Example:: 118 119 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 120 m.delete(2) # removes the first entry with key 2 121 str(m) # "{1:A,2:C}" 122 m.delete(99) # no-op 123 124 """ 125 it = self._t.find(key) 126 if not it.equals(self._t.end()): 127 self._t.erase(it.node) 128 129 def get(self, key: K, default: V | None = None) -> V | None: 130 """ 131 Return the value of the first entry with *key*, or *default* if absent. 132 133 Args: 134 key: Key to look up. 135 default: Value returned when *key* is not in the map. 136 137 Example:: 138 139 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 140 m.get(2) # "B" — first entry with key 2 141 m.get(4) # None 142 m.get(4, "Z") # "Z" 143 144 """ 145 it = self._t.find(key) 146 if not it.equals(self._t.end()): 147 return it.value 148 return default 149 150 def has(self, key: K) -> bool: 151 """ 152 @private Return True when at least one entry with *key* exists in the map. 153 154 Example:: 155 156 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 157 m.has(2) # True 158 m.has(4) # False 159 160 """ 161 it = self._t.find(key) 162 return not it.equals(self._t.end()) 163 164 def set(self, key: K, value: V) -> None: 165 """ 166 @private Add a new *(key, value)* entry, even when *key* already exists. 167 168 This is the defining behaviour of a multimap: duplicate keys are always 169 accepted, so calling ``set()`` twice with the same key creates two 170 distinct entries. 171 172 Example:: 173 174 m = TreeMultiMap() 175 m.set(1, "A") 176 m.set(1, "B") # second entry with key 1 177 list(m.values()) # ["A", "B"] 178 179 """ 180 n: TreeNode[K, V] = TreeNode() 181 n.key = key 182 n.value = value 183 self._t.insert_multi(n) 184 185 def items(self) -> PyIterator[tuple[K, V]]: 186 """ 187 Return a forward iterator over (key, value) pairs in ascending key order. 188 189 Example:: 190 191 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 192 for key, value in m.items(): 193 print(f"key: {key}, value: {value}") 194 # key: 1, value: A 195 # key: 2, value: B 196 # key: 2, value: C 197 198 """ 199 return self._t.items() 200 201 def keys(self) -> PyIterator[K]: 202 """ 203 Return a forward iterator over keys in ascending order (including duplicates). 204 205 Example:: 206 207 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 208 list(m.keys()) # [1, 2, 2] 209 list(m.keys().backwards()) # [2, 2, 1] 210 211 """ 212 return self._t.keys() 213 214 def values(self) -> PyIterator[V]: 215 """ 216 Return a forward iterator over values in ascending key order. 217 218 Example:: 219 220 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 221 list(m.values()) # ["A", "B", "C"] 222 list(m.values().backwards()) # ["C", "B", "A"] 223 224 """ 225 return self._t.values() 226 227 @property 228 def size(self) -> int: 229 """ 230 @private Total number of entries in the map, counting each duplicate separately. 231 232 Example:: 233 234 m = TreeMultiMap([[2, "B"], [2, "C"], [1, "A"]]) 235 m.size # 3 236 237 """ 238 return self._t.size() 239 240 def __getitem__(self, key: K) -> V: 241 """ 242 Return the value of the first entry with *key*. 243 244 Args: 245 key: Key to look up. 246 247 Returns: 248 Value of the first matching entry. 249 250 Raises: 251 KeyError: When *key* is not present. 252 253 Example:: 254 255 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 256 m[2] # "B" — first entry with key 2 257 m[4] # raises KeyError 258 259 """ 260 it = self._t.find(key) 261 if not it.equals(self._t.end()): 262 return it.value 263 raise KeyError(f"Key {key} not found") 264 265 def __setitem__(self, key: K, value: V) -> None: 266 """ 267 Add a new *(key, value)* entry (same as set()). 268 269 Unlike a dict, this never replaces an existing entry; it always adds a new one. 270 271 Args: 272 key: Key for the new entry. 273 value: Value to associate with the key. 274 275 Example:: 276 277 m = TreeMultiMap() 278 m[1] = "A" 279 m[1] = "B" # adds a second entry, does NOT replace 280 list(m.values()) # ["A", "B"] 281 282 """ 283 self.set(key, value) 284 285 def __contains__(self, key: K) -> bool: 286 """ 287 Return True if at least one entry with *key* exists. 288 289 Args: 290 key: Key to check. 291 292 Example:: 293 294 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 295 2 in m # True 296 4 in m # False 297 298 """ 299 return self.has(key) 300 301 def __iter__(self) -> PyIterator[K]: 302 """ 303 Iterate over (key, value) pairs in ascending key order. 304 305 Example:: 306 307 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 308 for key in m: 309 print(f"{key}") 310 # 1 311 # 2 312 # 2 313 314 """ 315 return self._t.keys() 316 317 def __len__(self) -> int: 318 """ 319 Return the total number of entries, counting each duplicate separately. 320 321 Example:: 322 323 m = TreeMultiMap([[2, "B"], [2, "C"], [1, "A"]]) 324 len(m) # 3 325 326 """ 327 return self._t.size() 328 329 def __str__(self) -> str: 330 """ 331 Return a string representation in the form {key1:value1,key2:value2,...}. 332 333 Duplicate keys appear multiple times in the output. 334 335 Example:: 336 337 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 338 str(m) # "{1:A,2:B,2:C}" 339 340 """ 341 return str(self._t) 342 343 def __repr__(self) -> str: 344 """ 345 Return a string representation of the container's contents. 346 347 Example:: 348 349 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 350 repr(m) # "{1:A,2:B,2:C}" 351 352 """ 353 return self.__str__() 354 355 def __delitem__(self, key: K) -> None: 356 """ 357 Remove **ONLY** the first entry with *key*, or raise KeyError when absent. 358 359 Args: 360 key: Key to remove. 361 362 Raises: 363 KeyError: When *key* is not present. 364 365 Example:: 366 367 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 368 del m[2] # removes first entry with key 2; m is now {1:A,2:C} 369 del m[99] # raises KeyError 370 371 """ 372 it = self._t.find(key) 373 if not it.equals(self._t.end()): 374 self._t.erase(it.node) 375 else: 376 raise KeyError(f"Key {key} not found") 377 378 def pop(self, key: K, default: V | None = None) -> V | None: 379 """ 380 Remove **ONLY** the first entry with *key* and return its value, or return *default*. 381 382 Args: 383 key: Key to remove. 384 default: Value to return when *key* is not present. 385 386 Example:: 387 388 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 389 m.pop(2) # "B", m is now {1:A,2:C} 390 m.pop(9) # None, m is unchanged 391 m.pop(9, "Z") # "Z", m is unchanged 392 393 """ 394 it = self._t.find(key) 395 if not it.equals(self._t.end()): 396 res = it.value 397 self._t.erase(it.node) 398 return res 399 return default 400 401 def popitem(self, key: K) -> tuple[K, V]: 402 """ 403 Remove *key* and return its first key-value tuple or raise KeyError. 404 405 Args: 406 key: Key to remove. 407 408 Example:: 409 410 m = TreeMap([[1, "A"], [2, "B"], [3, "C"]]) 411 m.popitem(2) # "(2,B)", m is now {1:A,3:C} 412 m.popitem(9) # raises KeyError 413 414 """ 415 iter = self.find(key) 416 if not iter.equals(self.end()): 417 k = iter.key 418 v = iter.value 419 self.erase(iter) 420 return (k, v) 421 raise KeyError(f"Key {key} not found") 422 423 # ------------------------------------------------------------------ 424 # Additional iteration 425 # ------------------------------------------------------------------ 426 427 def backwards(self) -> PyReverseIterator[K]: 428 """ 429 Return a reverse iterator over keys in descending key order (including duplicates). 430 431 Example:: 432 433 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 434 for key in m.backwards(): 435 print(key) 436 # 2 437 # 2 438 # 1 439 440 """ 441 return self._t.keys().backwards() 442 443 # ------------------------------------------------------------------ 444 # Custom comparator 445 # ------------------------------------------------------------------ 446 447 @property 448 def compare_func(self) -> Callable[[Any, Any], int]: 449 """ 450 @private The current 3-way comparison function used to order keys. 451 452 The function must accept two key arguments and return a negative 453 integer, zero, or a positive integer when the first key is less 454 than, equal to, or greater than the second key. 455 456 Setting this property clears all existing entries because the 457 current ordering is no longer valid. 458 459 Example:: 460 461 m = TreeMultiMap() 462 m.compare_func = lambda a, b: -1 if a < b else (1 if a > b else 0) 463 m.set(3, "C") 464 m.set(1, "A") 465 list(m.keys()) # [1, 3] 466 467 """ 468 return self._t.compare 469 470 @compare_func.setter 471 def compare_func(self, func: Callable[[Any, Any], int]) -> None: 472 """@private Replace the comparison function and clear all entries.""" 473 self.clear() 474 self._t.compare = func 475 476 # ------------------------------------------------------------------ 477 # STL-style iterators 478 # ------------------------------------------------------------------ 479 480 def begin(self) -> TreeIterator[K, V]: 481 """ 482 Return a forward STL-like iterator to the first entry. 483 484 Example:: 485 486 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 487 it = m.begin() 488 while not it.equals(m.end()): 489 print(f"key: {it.key}, value: {it.value}") 490 it.next() 491 # key: 1, value: A 492 # key: 2, value: B 493 # key: 2, value: C 494 495 """ 496 return self._t.begin() 497 498 def end(self) -> TreeIterator[K, V]: 499 """ 500 Return a forward STL-like iterator past the last entry. 501 502 Example:: 503 504 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 505 it = m.begin() 506 while not it.equals(m.end()): 507 print(f"key: {it.key}, value: {it.value}") 508 it.next() 509 510 """ 511 return self._t.end() 512 513 def find(self, key: K) -> TreeIterator[K, V]: 514 """ 515 Return a forward iterator to the first entry with *key*, or end() if absent. 516 517 When multiple entries share the same key, the iterator points to the first one. 518 Use lower_bound() / upper_bound() to iterate over all entries with that key. 519 520 Example:: 521 522 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 523 it = m.find(2) 524 if not it.equals(m.end()): 525 print(f"key: {it.key}, value: {it.value}") # key: 2, value: B 526 m.find(99).equals(m.end()) # True 527 528 """ 529 return self._t.find(key) 530 531 def insert_unique(self, key: K, value: V) -> InsertionResult[TreeIterator[K, V]]: 532 """ 533 Insert *(key, value)* only when *key* is not already present. 534 535 Returns: 536 InsertionResult with was_added=True when the key was new; 537 was_added=False when any entry with that key already existed. 538 539 Example:: 540 541 m = TreeMultiMap() 542 res = m.insert_unique(1, "A") 543 res.was_added # True 544 res2 = m.insert_unique(1, "B") 545 res2.was_added # False — key 1 already exists 546 547 """ 548 n: TreeNode[K, V] = TreeNode() 549 n.key = key 550 n.value = value 551 return self._t.insert_unique(n) 552 553 def insert_or_replace(self, key: K, value: V) -> InsertionResult[TreeIterator[K, V]]: 554 """ 555 Insert *(key, value)*, replacing the first existing entry when *key* already exists. 556 557 Returns: 558 InsertionResult with was_added=True on new insertion, or 559 was_replaced=True and the updated iterator on replacement. 560 561 Example:: 562 563 m = TreeMultiMap() 564 res = m.insert_or_replace(1, "A") 565 res.was_added # True 566 res2 = m.insert_or_replace(1, "B") 567 res2.was_replaced # True 568 res2.iterator.value # "B" 569 570 """ 571 n: TreeNode[K, V] = TreeNode() 572 n.key = key 573 n.value = value 574 return self._t.insert_or_replace(n) 575 576 def insert_multi(self, key: K, value: V) -> InsertionResult[TreeIterator[K, V]]: 577 """ 578 Insert *(key, value)* unconditionally, always creating a new entry. 579 580 This is the multi-key insertion that makes TreeMultiMap distinct from TreeMap. 581 582 Returns: 583 InsertionResult with was_added=True and an iterator to the new entry. 584 585 Example:: 586 587 m = TreeMultiMap() 588 res = m.insert_multi(1, "A") 589 res.was_added # True 590 res2 = m.insert_multi(1, "B") 591 res2.was_added # True — second entry with key 1 added 592 res2.iterator.prev() 593 res2.iterator.value # "A" 594 595 """ 596 n: TreeNode[K, V] = TreeNode() 597 n.key = key 598 n.value = value 599 return self._t.insert_multi(n) 600 601 def erase(self, iterator: TreeIterator[K, V]) -> None: 602 """ 603 Remove the entry pointed to by *iterator*. 604 605 Example:: 606 607 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 608 it = m.find(2) 609 m.erase(it) 610 str(m) # "{1:A,2:C}" 611 612 """ 613 self._t.erase(iterator.node) 614 615 def lower_bound(self, key: K) -> TreeIterator[K, V]: 616 """ 617 Return an STL-like iterator to the first entry with key >= *key*, or end(). 618 619 Combined with upper_bound(), this gives a half-open range over all 620 entries that share the same key. 621 622 Example:: 623 624 m = TreeMultiMap([[2, "B1"], [2, "B2"], [4, "D"]]) 625 lo = m.lower_bound(2) 626 hi = m.upper_bound(2) 627 it = lo 628 while not it.equals(hi): 629 print(it.value) # B1, B2 630 it.next() 631 632 """ 633 return self._t.lower_bound(key) 634 635 def rbegin(self) -> ReverseIterator[K, V]: 636 """ 637 Return a reverse STL-like iterator to the entry with the largest key. 638 639 Example:: 640 641 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 642 it = m.rbegin() 643 while not it.equals(m.rend()): 644 print(f"key: {it.key}, value: {it.value}") 645 it.next() 646 # key: 2, value: C 647 # key: 2, value: B 648 # key: 1, value: A 649 650 """ 651 return self._t.rbegin() 652 653 def rend(self) -> ReverseIterator[K, V]: 654 """ 655 Return a reverse STL-like iterator before the entry with the smallest key. 656 657 Example:: 658 659 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 660 it = m.rbegin() 661 while not it.equals(m.rend()): 662 print(f"key: {it.key}, value: {it.value}") 663 it.next() 664 665 """ 666 return self._t.rend() 667 668 def upper_bound(self, key: K) -> TreeIterator[K, V]: 669 """ 670 Return an STL-like iterator to the first entry with key > *key*, or end(). 671 672 Combined with lower_bound(), this gives a half-open range over all 673 entries that share the same key. 674 675 Example:: 676 677 m = TreeMultiMap([[2, "B1"], [2, "B2"], [4, "D"]]) 678 lo = m.lower_bound(2) 679 hi = m.upper_bound(2) 680 it = lo 681 while not it.equals(hi): 682 print(it.value) # B1, B2 683 it.next() 684 685 """ 686 return self._t.upper_bound(key) 687 688 def first(self) -> tuple[K, V] | None: 689 """ 690 Return the first (key, value) pair, or None when the map is empty. 691 692 Example:: 693 694 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 695 key, value = m.first() # (1, "A") 696 TreeMultiMap().first() # None 697 698 """ 699 return self._t.first() 700 701 def last(self) -> tuple[K, V] | None: 702 """ 703 Return the last (key, value) pair, or None when the map is empty. 704 705 Example:: 706 707 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 708 key, value = m.last() # (2, "C") 709 TreeMultiMap().last() # None 710 711 """ 712 return self._t.last() 713 714 def __or__(self, other: Any) -> TreeMultiMap[K, V]: 715 """ 716 Return a new multimap containing all entries from this map followed by all from *other*. 717 718 All entries are added via insert_multi, so duplicates are preserved. 719 720 Example:: 721 722 m1 = TreeMultiMap([[1, "A"], [2, "B"]]) 723 m2 = TreeMultiMap([[2, "X"], [3, "C"]]) 724 m3 = m1 | m2 725 str(m3) # "{1:A,2:B,2:X,3:C}" 726 727 """ 728 res = TreeMultiMap[K, V](self) 729 if isinstance(other, (dict, UserDict, TreeMultiMap)) or hasattr(other, "__iter__"): 730 res.update(other) 731 else: 732 return NotImplemented 733 return res 734 735 def __ror__(self, other: Any) -> TreeMultiMap[K, V]: 736 """ 737 Return a union multimap when this TreeMultiMap is on the right-hand side of ``|``. 738 739 *other*'s entries are inserted first, then this map's entries are appended. 740 741 Example:: 742 743 m = TreeMultiMap([[2, "X"], [3, "C"]]) 744 result = {1: "A", 2: "B"} | m 745 str(result) # "{1:A,2:B,2:X,3:C}" 746 747 """ 748 res = TreeMultiMap[K, V]() 749 if isinstance(other, (dict, UserDict, TreeMultiMap)) or hasattr(other, "__iter__"): 750 res.update(other) 751 else: 752 return NotImplemented 753 res.update(self) 754 return res 755 756 def __ior__(self, other: Any) -> TreeMultiMap[K, V]: 757 """ 758 Add all entries from *other* to this multimap in-place. 759 760 Example:: 761 762 m = TreeMultiMap([[1, "A"], [2, "B"]]) 763 m |= {2: "X", 3: "C"} 764 str(m) # "{1:A,2:B,2:X,3:C}" 765 766 """ 767 if isinstance(other, (dict, UserDict, TreeMultiMap)) or hasattr(other, "__iter__"): 768 self.update(other) 769 else: 770 return NotImplemented 771 return self 772 773 def __copy__(self) -> TreeMultiMap[K, V]: 774 """ 775 Create a shallow copy, preserving all entries including duplicates. 776 777 Example:: 778 779 import copy 780 781 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 782 m2 = copy.copy(m) 783 m2.set(3, "D") 784 str(m) # "{1:A,2:B,2:C}" — original unchanged 785 str(m2) # "{1:A,2:B,2:C,3:D}" 786 787 """ 788 return TreeMultiMap[K, V](self.items())
18class TreeMultiMap[K, V](Collection[K]): 19 """ 20 Ordered map allowing multiple entries with the same key, backed by a red-black tree. 21 22 Unlike TreeMap, duplicate keys are permitted. Entries with equal keys appear 23 in insertion order and are kept in their key's sorted position relative to 24 entries with different keys. Lookup, insertion, and deletion are all O(log n). 25 26 Example:: 27 28 m = TreeMultiMap() 29 m[2] = "b1" 30 m[2] = "b2" 31 m[1] = "a" 32 for key, value in m: 33 print(f"{key}: {value}") 34 # 1: a 35 # 2: b1 36 # 2: b2 37 """ 38 39 def __init__(self, iterable: Iterable[tuple[K, V]] | None = None, **kwargs) -> None: 40 """ 41 Create an empty multimap, or pre-populate it from an iterable of (key, value) pairs. 42 43 Each pair in *iterable* is inserted independently; duplicate keys are kept. 44 45 Args: 46 iterable: Optional iterable of (key, value) tuples. 47 kwargs: Another way to provide key-value pairs. 48 49 Raises: 50 TypeError: When *iterable* is not iterable. 51 52 Example:: 53 54 m = TreeMultiMap() 55 m = TreeMultiMap([[2, "B"], [1, "A"], [2, "B2"]]) 56 m = TreeMultiMap({2: "B", 1: "A", 3: "C"}) 57 m = TreeMultiMap(A=1, B=2) # {"A": 1, "B": 2} 58 59 """ 60 self._t: Tree[K, V] = Tree() 61 self._t.value_policy = KeyValuePolicy() 62 if iterable is not None: 63 self.update(iterable) 64 if kwargs: 65 self.update(kwargs.items()) 66 67 def update(self, iterable: Iterable[tuple[K, V]]) -> None: 68 """ 69 Add all contents from the iterable of (key, value) pairs. 70 71 Args: 72 iterable: Optional iterable of (key, value) tuples. 73 74 Raises: 75 TypeError: When *iterable* is not iterable. 76 77 Example:: 78 79 TreeMultiMap().update(TreeMultiMap({2: "B", 1: "A", 3: "C"})) 80 TreeMultiMap().update({2: "B", 1: "A", 3: "C"}) 81 TreeMultiMap().update({2: "B", 1: "A", 3: "C"}.items()) 82 TreeMultiMap().update([[2, "B"], [1, "A"], [3, "C"]]) 83 84 """ 85 if isinstance(iterable, (dict, UserDict, TreeMultiMap)): 86 for k, v in iterable.items(): 87 self.set(k, v) 88 elif hasattr(iterable, "__iter__"): 89 for k, v in iterable: 90 self.set(k, v) 91 else: 92 raise TypeError("TreeMultiMap accepts only iterable objects") 93 94 # ------------------------------------------------------------------ 95 # Python dict-compatible methods 96 # ------------------------------------------------------------------ 97 98 def clear(self) -> None: 99 """ 100 Remove all key-value pairs. 101 102 Example:: 103 104 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 105 m.clear() 106 len(m) # 0 107 108 """ 109 self._t.clear() 110 111 def delete(self, key: K) -> None: 112 """ 113 @private Remove the first entry with *key*; does nothing if the key is absent. 114 115 When multiple entries share the same key, only the first one is removed. 116 Call repeatedly or use erase() to remove all of them. 117 118 Example:: 119 120 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 121 m.delete(2) # removes the first entry with key 2 122 str(m) # "{1:A,2:C}" 123 m.delete(99) # no-op 124 125 """ 126 it = self._t.find(key) 127 if not it.equals(self._t.end()): 128 self._t.erase(it.node) 129 130 def get(self, key: K, default: V | None = None) -> V | None: 131 """ 132 Return the value of the first entry with *key*, or *default* if absent. 133 134 Args: 135 key: Key to look up. 136 default: Value returned when *key* is not in the map. 137 138 Example:: 139 140 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 141 m.get(2) # "B" — first entry with key 2 142 m.get(4) # None 143 m.get(4, "Z") # "Z" 144 145 """ 146 it = self._t.find(key) 147 if not it.equals(self._t.end()): 148 return it.value 149 return default 150 151 def has(self, key: K) -> bool: 152 """ 153 @private Return True when at least one entry with *key* exists in the map. 154 155 Example:: 156 157 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 158 m.has(2) # True 159 m.has(4) # False 160 161 """ 162 it = self._t.find(key) 163 return not it.equals(self._t.end()) 164 165 def set(self, key: K, value: V) -> None: 166 """ 167 @private Add a new *(key, value)* entry, even when *key* already exists. 168 169 This is the defining behaviour of a multimap: duplicate keys are always 170 accepted, so calling ``set()`` twice with the same key creates two 171 distinct entries. 172 173 Example:: 174 175 m = TreeMultiMap() 176 m.set(1, "A") 177 m.set(1, "B") # second entry with key 1 178 list(m.values()) # ["A", "B"] 179 180 """ 181 n: TreeNode[K, V] = TreeNode() 182 n.key = key 183 n.value = value 184 self._t.insert_multi(n) 185 186 def items(self) -> PyIterator[tuple[K, V]]: 187 """ 188 Return a forward iterator over (key, value) pairs in ascending key order. 189 190 Example:: 191 192 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 193 for key, value in m.items(): 194 print(f"key: {key}, value: {value}") 195 # key: 1, value: A 196 # key: 2, value: B 197 # key: 2, value: C 198 199 """ 200 return self._t.items() 201 202 def keys(self) -> PyIterator[K]: 203 """ 204 Return a forward iterator over keys in ascending order (including duplicates). 205 206 Example:: 207 208 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 209 list(m.keys()) # [1, 2, 2] 210 list(m.keys().backwards()) # [2, 2, 1] 211 212 """ 213 return self._t.keys() 214 215 def values(self) -> PyIterator[V]: 216 """ 217 Return a forward iterator over values in ascending key order. 218 219 Example:: 220 221 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 222 list(m.values()) # ["A", "B", "C"] 223 list(m.values().backwards()) # ["C", "B", "A"] 224 225 """ 226 return self._t.values() 227 228 @property 229 def size(self) -> int: 230 """ 231 @private Total number of entries in the map, counting each duplicate separately. 232 233 Example:: 234 235 m = TreeMultiMap([[2, "B"], [2, "C"], [1, "A"]]) 236 m.size # 3 237 238 """ 239 return self._t.size() 240 241 def __getitem__(self, key: K) -> V: 242 """ 243 Return the value of the first entry with *key*. 244 245 Args: 246 key: Key to look up. 247 248 Returns: 249 Value of the first matching entry. 250 251 Raises: 252 KeyError: When *key* is not present. 253 254 Example:: 255 256 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 257 m[2] # "B" — first entry with key 2 258 m[4] # raises KeyError 259 260 """ 261 it = self._t.find(key) 262 if not it.equals(self._t.end()): 263 return it.value 264 raise KeyError(f"Key {key} not found") 265 266 def __setitem__(self, key: K, value: V) -> None: 267 """ 268 Add a new *(key, value)* entry (same as set()). 269 270 Unlike a dict, this never replaces an existing entry; it always adds a new one. 271 272 Args: 273 key: Key for the new entry. 274 value: Value to associate with the key. 275 276 Example:: 277 278 m = TreeMultiMap() 279 m[1] = "A" 280 m[1] = "B" # adds a second entry, does NOT replace 281 list(m.values()) # ["A", "B"] 282 283 """ 284 self.set(key, value) 285 286 def __contains__(self, key: K) -> bool: 287 """ 288 Return True if at least one entry with *key* exists. 289 290 Args: 291 key: Key to check. 292 293 Example:: 294 295 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 296 2 in m # True 297 4 in m # False 298 299 """ 300 return self.has(key) 301 302 def __iter__(self) -> PyIterator[K]: 303 """ 304 Iterate over (key, value) pairs in ascending key order. 305 306 Example:: 307 308 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 309 for key in m: 310 print(f"{key}") 311 # 1 312 # 2 313 # 2 314 315 """ 316 return self._t.keys() 317 318 def __len__(self) -> int: 319 """ 320 Return the total number of entries, counting each duplicate separately. 321 322 Example:: 323 324 m = TreeMultiMap([[2, "B"], [2, "C"], [1, "A"]]) 325 len(m) # 3 326 327 """ 328 return self._t.size() 329 330 def __str__(self) -> str: 331 """ 332 Return a string representation in the form {key1:value1,key2:value2,...}. 333 334 Duplicate keys appear multiple times in the output. 335 336 Example:: 337 338 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 339 str(m) # "{1:A,2:B,2:C}" 340 341 """ 342 return str(self._t) 343 344 def __repr__(self) -> str: 345 """ 346 Return a string representation of the container's contents. 347 348 Example:: 349 350 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 351 repr(m) # "{1:A,2:B,2:C}" 352 353 """ 354 return self.__str__() 355 356 def __delitem__(self, key: K) -> None: 357 """ 358 Remove **ONLY** the first entry with *key*, or raise KeyError when absent. 359 360 Args: 361 key: Key to remove. 362 363 Raises: 364 KeyError: When *key* is not present. 365 366 Example:: 367 368 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 369 del m[2] # removes first entry with key 2; m is now {1:A,2:C} 370 del m[99] # raises KeyError 371 372 """ 373 it = self._t.find(key) 374 if not it.equals(self._t.end()): 375 self._t.erase(it.node) 376 else: 377 raise KeyError(f"Key {key} not found") 378 379 def pop(self, key: K, default: V | None = None) -> V | None: 380 """ 381 Remove **ONLY** the first entry with *key* and return its value, or return *default*. 382 383 Args: 384 key: Key to remove. 385 default: Value to return when *key* is not present. 386 387 Example:: 388 389 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 390 m.pop(2) # "B", m is now {1:A,2:C} 391 m.pop(9) # None, m is unchanged 392 m.pop(9, "Z") # "Z", m is unchanged 393 394 """ 395 it = self._t.find(key) 396 if not it.equals(self._t.end()): 397 res = it.value 398 self._t.erase(it.node) 399 return res 400 return default 401 402 def popitem(self, key: K) -> tuple[K, V]: 403 """ 404 Remove *key* and return its first key-value tuple or raise KeyError. 405 406 Args: 407 key: Key to remove. 408 409 Example:: 410 411 m = TreeMap([[1, "A"], [2, "B"], [3, "C"]]) 412 m.popitem(2) # "(2,B)", m is now {1:A,3:C} 413 m.popitem(9) # raises KeyError 414 415 """ 416 iter = self.find(key) 417 if not iter.equals(self.end()): 418 k = iter.key 419 v = iter.value 420 self.erase(iter) 421 return (k, v) 422 raise KeyError(f"Key {key} not found") 423 424 # ------------------------------------------------------------------ 425 # Additional iteration 426 # ------------------------------------------------------------------ 427 428 def backwards(self) -> PyReverseIterator[K]: 429 """ 430 Return a reverse iterator over keys in descending key order (including duplicates). 431 432 Example:: 433 434 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 435 for key in m.backwards(): 436 print(key) 437 # 2 438 # 2 439 # 1 440 441 """ 442 return self._t.keys().backwards() 443 444 # ------------------------------------------------------------------ 445 # Custom comparator 446 # ------------------------------------------------------------------ 447 448 @property 449 def compare_func(self) -> Callable[[Any, Any], int]: 450 """ 451 @private The current 3-way comparison function used to order keys. 452 453 The function must accept two key arguments and return a negative 454 integer, zero, or a positive integer when the first key is less 455 than, equal to, or greater than the second key. 456 457 Setting this property clears all existing entries because the 458 current ordering is no longer valid. 459 460 Example:: 461 462 m = TreeMultiMap() 463 m.compare_func = lambda a, b: -1 if a < b else (1 if a > b else 0) 464 m.set(3, "C") 465 m.set(1, "A") 466 list(m.keys()) # [1, 3] 467 468 """ 469 return self._t.compare 470 471 @compare_func.setter 472 def compare_func(self, func: Callable[[Any, Any], int]) -> None: 473 """@private Replace the comparison function and clear all entries.""" 474 self.clear() 475 self._t.compare = func 476 477 # ------------------------------------------------------------------ 478 # STL-style iterators 479 # ------------------------------------------------------------------ 480 481 def begin(self) -> TreeIterator[K, V]: 482 """ 483 Return a forward STL-like iterator to the first entry. 484 485 Example:: 486 487 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 488 it = m.begin() 489 while not it.equals(m.end()): 490 print(f"key: {it.key}, value: {it.value}") 491 it.next() 492 # key: 1, value: A 493 # key: 2, value: B 494 # key: 2, value: C 495 496 """ 497 return self._t.begin() 498 499 def end(self) -> TreeIterator[K, V]: 500 """ 501 Return a forward STL-like iterator past the last entry. 502 503 Example:: 504 505 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 506 it = m.begin() 507 while not it.equals(m.end()): 508 print(f"key: {it.key}, value: {it.value}") 509 it.next() 510 511 """ 512 return self._t.end() 513 514 def find(self, key: K) -> TreeIterator[K, V]: 515 """ 516 Return a forward iterator to the first entry with *key*, or end() if absent. 517 518 When multiple entries share the same key, the iterator points to the first one. 519 Use lower_bound() / upper_bound() to iterate over all entries with that key. 520 521 Example:: 522 523 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 524 it = m.find(2) 525 if not it.equals(m.end()): 526 print(f"key: {it.key}, value: {it.value}") # key: 2, value: B 527 m.find(99).equals(m.end()) # True 528 529 """ 530 return self._t.find(key) 531 532 def insert_unique(self, key: K, value: V) -> InsertionResult[TreeIterator[K, V]]: 533 """ 534 Insert *(key, value)* only when *key* is not already present. 535 536 Returns: 537 InsertionResult with was_added=True when the key was new; 538 was_added=False when any entry with that key already existed. 539 540 Example:: 541 542 m = TreeMultiMap() 543 res = m.insert_unique(1, "A") 544 res.was_added # True 545 res2 = m.insert_unique(1, "B") 546 res2.was_added # False — key 1 already exists 547 548 """ 549 n: TreeNode[K, V] = TreeNode() 550 n.key = key 551 n.value = value 552 return self._t.insert_unique(n) 553 554 def insert_or_replace(self, key: K, value: V) -> InsertionResult[TreeIterator[K, V]]: 555 """ 556 Insert *(key, value)*, replacing the first existing entry when *key* already exists. 557 558 Returns: 559 InsertionResult with was_added=True on new insertion, or 560 was_replaced=True and the updated iterator on replacement. 561 562 Example:: 563 564 m = TreeMultiMap() 565 res = m.insert_or_replace(1, "A") 566 res.was_added # True 567 res2 = m.insert_or_replace(1, "B") 568 res2.was_replaced # True 569 res2.iterator.value # "B" 570 571 """ 572 n: TreeNode[K, V] = TreeNode() 573 n.key = key 574 n.value = value 575 return self._t.insert_or_replace(n) 576 577 def insert_multi(self, key: K, value: V) -> InsertionResult[TreeIterator[K, V]]: 578 """ 579 Insert *(key, value)* unconditionally, always creating a new entry. 580 581 This is the multi-key insertion that makes TreeMultiMap distinct from TreeMap. 582 583 Returns: 584 InsertionResult with was_added=True and an iterator to the new entry. 585 586 Example:: 587 588 m = TreeMultiMap() 589 res = m.insert_multi(1, "A") 590 res.was_added # True 591 res2 = m.insert_multi(1, "B") 592 res2.was_added # True — second entry with key 1 added 593 res2.iterator.prev() 594 res2.iterator.value # "A" 595 596 """ 597 n: TreeNode[K, V] = TreeNode() 598 n.key = key 599 n.value = value 600 return self._t.insert_multi(n) 601 602 def erase(self, iterator: TreeIterator[K, V]) -> None: 603 """ 604 Remove the entry pointed to by *iterator*. 605 606 Example:: 607 608 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 609 it = m.find(2) 610 m.erase(it) 611 str(m) # "{1:A,2:C}" 612 613 """ 614 self._t.erase(iterator.node) 615 616 def lower_bound(self, key: K) -> TreeIterator[K, V]: 617 """ 618 Return an STL-like iterator to the first entry with key >= *key*, or end(). 619 620 Combined with upper_bound(), this gives a half-open range over all 621 entries that share the same key. 622 623 Example:: 624 625 m = TreeMultiMap([[2, "B1"], [2, "B2"], [4, "D"]]) 626 lo = m.lower_bound(2) 627 hi = m.upper_bound(2) 628 it = lo 629 while not it.equals(hi): 630 print(it.value) # B1, B2 631 it.next() 632 633 """ 634 return self._t.lower_bound(key) 635 636 def rbegin(self) -> ReverseIterator[K, V]: 637 """ 638 Return a reverse STL-like iterator to the entry with the largest key. 639 640 Example:: 641 642 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 643 it = m.rbegin() 644 while not it.equals(m.rend()): 645 print(f"key: {it.key}, value: {it.value}") 646 it.next() 647 # key: 2, value: C 648 # key: 2, value: B 649 # key: 1, value: A 650 651 """ 652 return self._t.rbegin() 653 654 def rend(self) -> ReverseIterator[K, V]: 655 """ 656 Return a reverse STL-like iterator before the entry with the smallest key. 657 658 Example:: 659 660 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 661 it = m.rbegin() 662 while not it.equals(m.rend()): 663 print(f"key: {it.key}, value: {it.value}") 664 it.next() 665 666 """ 667 return self._t.rend() 668 669 def upper_bound(self, key: K) -> TreeIterator[K, V]: 670 """ 671 Return an STL-like iterator to the first entry with key > *key*, or end(). 672 673 Combined with lower_bound(), this gives a half-open range over all 674 entries that share the same key. 675 676 Example:: 677 678 m = TreeMultiMap([[2, "B1"], [2, "B2"], [4, "D"]]) 679 lo = m.lower_bound(2) 680 hi = m.upper_bound(2) 681 it = lo 682 while not it.equals(hi): 683 print(it.value) # B1, B2 684 it.next() 685 686 """ 687 return self._t.upper_bound(key) 688 689 def first(self) -> tuple[K, V] | None: 690 """ 691 Return the first (key, value) pair, or None when the map is empty. 692 693 Example:: 694 695 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 696 key, value = m.first() # (1, "A") 697 TreeMultiMap().first() # None 698 699 """ 700 return self._t.first() 701 702 def last(self) -> tuple[K, V] | None: 703 """ 704 Return the last (key, value) pair, or None when the map is empty. 705 706 Example:: 707 708 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 709 key, value = m.last() # (2, "C") 710 TreeMultiMap().last() # None 711 712 """ 713 return self._t.last() 714 715 def __or__(self, other: Any) -> TreeMultiMap[K, V]: 716 """ 717 Return a new multimap containing all entries from this map followed by all from *other*. 718 719 All entries are added via insert_multi, so duplicates are preserved. 720 721 Example:: 722 723 m1 = TreeMultiMap([[1, "A"], [2, "B"]]) 724 m2 = TreeMultiMap([[2, "X"], [3, "C"]]) 725 m3 = m1 | m2 726 str(m3) # "{1:A,2:B,2:X,3:C}" 727 728 """ 729 res = TreeMultiMap[K, V](self) 730 if isinstance(other, (dict, UserDict, TreeMultiMap)) or hasattr(other, "__iter__"): 731 res.update(other) 732 else: 733 return NotImplemented 734 return res 735 736 def __ror__(self, other: Any) -> TreeMultiMap[K, V]: 737 """ 738 Return a union multimap when this TreeMultiMap is on the right-hand side of ``|``. 739 740 *other*'s entries are inserted first, then this map's entries are appended. 741 742 Example:: 743 744 m = TreeMultiMap([[2, "X"], [3, "C"]]) 745 result = {1: "A", 2: "B"} | m 746 str(result) # "{1:A,2:B,2:X,3:C}" 747 748 """ 749 res = TreeMultiMap[K, V]() 750 if isinstance(other, (dict, UserDict, TreeMultiMap)) or hasattr(other, "__iter__"): 751 res.update(other) 752 else: 753 return NotImplemented 754 res.update(self) 755 return res 756 757 def __ior__(self, other: Any) -> TreeMultiMap[K, V]: 758 """ 759 Add all entries from *other* to this multimap in-place. 760 761 Example:: 762 763 m = TreeMultiMap([[1, "A"], [2, "B"]]) 764 m |= {2: "X", 3: "C"} 765 str(m) # "{1:A,2:B,2:X,3:C}" 766 767 """ 768 if isinstance(other, (dict, UserDict, TreeMultiMap)) or hasattr(other, "__iter__"): 769 self.update(other) 770 else: 771 return NotImplemented 772 return self 773 774 def __copy__(self) -> TreeMultiMap[K, V]: 775 """ 776 Create a shallow copy, preserving all entries including duplicates. 777 778 Example:: 779 780 import copy 781 782 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 783 m2 = copy.copy(m) 784 m2.set(3, "D") 785 str(m) # "{1:A,2:B,2:C}" — original unchanged 786 str(m2) # "{1:A,2:B,2:C,3:D}" 787 788 """ 789 return TreeMultiMap[K, V](self.items())
Ordered map allowing multiple entries with the same key, backed by a red-black tree.
Unlike TreeMap, duplicate keys are permitted. Entries with equal keys appear in insertion order and are kept in their key's sorted position relative to entries with different keys. Lookup, insertion, and deletion are all O(log n).
Example::
m = TreeMultiMap()
m[2] = "b1"
m[2] = "b2"
m[1] = "a"
for key, value in m:
print(f"{key}: {value}")
# 1: a
# 2: b1
# 2: b2
39 def __init__(self, iterable: Iterable[tuple[K, V]] | None = None, **kwargs) -> None: 40 """ 41 Create an empty multimap, or pre-populate it from an iterable of (key, value) pairs. 42 43 Each pair in *iterable* is inserted independently; duplicate keys are kept. 44 45 Args: 46 iterable: Optional iterable of (key, value) tuples. 47 kwargs: Another way to provide key-value pairs. 48 49 Raises: 50 TypeError: When *iterable* is not iterable. 51 52 Example:: 53 54 m = TreeMultiMap() 55 m = TreeMultiMap([[2, "B"], [1, "A"], [2, "B2"]]) 56 m = TreeMultiMap({2: "B", 1: "A", 3: "C"}) 57 m = TreeMultiMap(A=1, B=2) # {"A": 1, "B": 2} 58 59 """ 60 self._t: Tree[K, V] = Tree() 61 self._t.value_policy = KeyValuePolicy() 62 if iterable is not None: 63 self.update(iterable) 64 if kwargs: 65 self.update(kwargs.items())
Create an empty multimap, or pre-populate it from an iterable of (key, value) pairs.
Each pair in iterable is inserted independently; duplicate keys are kept.
Args: iterable: Optional iterable of (key, value) tuples. kwargs: Another way to provide key-value pairs.
Raises: TypeError: When iterable is not iterable.
Example::
m = TreeMultiMap()
m = TreeMultiMap([[2, "B"], [1, "A"], [2, "B2"]])
m = TreeMultiMap({2: "B", 1: "A", 3: "C"})
m = TreeMultiMap(A=1, B=2) # {"A": 1, "B": 2}
67 def update(self, iterable: Iterable[tuple[K, V]]) -> None: 68 """ 69 Add all contents from the iterable of (key, value) pairs. 70 71 Args: 72 iterable: Optional iterable of (key, value) tuples. 73 74 Raises: 75 TypeError: When *iterable* is not iterable. 76 77 Example:: 78 79 TreeMultiMap().update(TreeMultiMap({2: "B", 1: "A", 3: "C"})) 80 TreeMultiMap().update({2: "B", 1: "A", 3: "C"}) 81 TreeMultiMap().update({2: "B", 1: "A", 3: "C"}.items()) 82 TreeMultiMap().update([[2, "B"], [1, "A"], [3, "C"]]) 83 84 """ 85 if isinstance(iterable, (dict, UserDict, TreeMultiMap)): 86 for k, v in iterable.items(): 87 self.set(k, v) 88 elif hasattr(iterable, "__iter__"): 89 for k, v in iterable: 90 self.set(k, v) 91 else: 92 raise TypeError("TreeMultiMap accepts only iterable objects")
Add all contents from the iterable of (key, value) pairs.
Args: iterable: Optional iterable of (key, value) tuples.
Raises: TypeError: When iterable is not iterable.
Example::
TreeMultiMap().update(TreeMultiMap({2: "B", 1: "A", 3: "C"}))
TreeMultiMap().update({2: "B", 1: "A", 3: "C"})
TreeMultiMap().update({2: "B", 1: "A", 3: "C"}.items())
TreeMultiMap().update([[2, "B"], [1, "A"], [3, "C"]])
98 def clear(self) -> None: 99 """ 100 Remove all key-value pairs. 101 102 Example:: 103 104 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 105 m.clear() 106 len(m) # 0 107 108 """ 109 self._t.clear()
Remove all key-value pairs.
Example::
m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]])
m.clear()
len(m) # 0
130 def get(self, key: K, default: V | None = None) -> V | None: 131 """ 132 Return the value of the first entry with *key*, or *default* if absent. 133 134 Args: 135 key: Key to look up. 136 default: Value returned when *key* is not in the map. 137 138 Example:: 139 140 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 141 m.get(2) # "B" — first entry with key 2 142 m.get(4) # None 143 m.get(4, "Z") # "Z" 144 145 """ 146 it = self._t.find(key) 147 if not it.equals(self._t.end()): 148 return it.value 149 return default
Return the value of the first entry with key, or default if absent.
Args: key: Key to look up. default: Value returned when key is not in the map.
Example::
m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]])
m.get(2) # "B" — first entry with key 2
m.get(4) # None
m.get(4, "Z") # "Z"
186 def items(self) -> PyIterator[tuple[K, V]]: 187 """ 188 Return a forward iterator over (key, value) pairs in ascending key order. 189 190 Example:: 191 192 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 193 for key, value in m.items(): 194 print(f"key: {key}, value: {value}") 195 # key: 1, value: A 196 # key: 2, value: B 197 # key: 2, value: C 198 199 """ 200 return self._t.items()
Return a forward iterator over (key, value) pairs in ascending key order.
Example::
m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]])
for key, value in m.items():
print(f"key: {key}, value: {value}")
# key: 1, value: A
# key: 2, value: B
# key: 2, value: C
202 def keys(self) -> PyIterator[K]: 203 """ 204 Return a forward iterator over keys in ascending order (including duplicates). 205 206 Example:: 207 208 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 209 list(m.keys()) # [1, 2, 2] 210 list(m.keys().backwards()) # [2, 2, 1] 211 212 """ 213 return self._t.keys()
Return a forward iterator over keys in ascending order (including duplicates).
Example::
m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]])
list(m.keys()) # [1, 2, 2]
list(m.keys().backwards()) # [2, 2, 1]
215 def values(self) -> PyIterator[V]: 216 """ 217 Return a forward iterator over values in ascending key order. 218 219 Example:: 220 221 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 222 list(m.values()) # ["A", "B", "C"] 223 list(m.values().backwards()) # ["C", "B", "A"] 224 225 """ 226 return self._t.values()
Return a forward iterator over values in ascending key order.
Example::
m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]])
list(m.values()) # ["A", "B", "C"]
list(m.values().backwards()) # ["C", "B", "A"]
379 def pop(self, key: K, default: V | None = None) -> V | None: 380 """ 381 Remove **ONLY** the first entry with *key* and return its value, or return *default*. 382 383 Args: 384 key: Key to remove. 385 default: Value to return when *key* is not present. 386 387 Example:: 388 389 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 390 m.pop(2) # "B", m is now {1:A,2:C} 391 m.pop(9) # None, m is unchanged 392 m.pop(9, "Z") # "Z", m is unchanged 393 394 """ 395 it = self._t.find(key) 396 if not it.equals(self._t.end()): 397 res = it.value 398 self._t.erase(it.node) 399 return res 400 return default
Remove ONLY the first entry with key and return its value, or return default.
Args: key: Key to remove. default: Value to return when key is not present.
Example::
m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]])
m.pop(2) # "B", m is now {1:A,2:C}
m.pop(9) # None, m is unchanged
m.pop(9, "Z") # "Z", m is unchanged
402 def popitem(self, key: K) -> tuple[K, V]: 403 """ 404 Remove *key* and return its first key-value tuple or raise KeyError. 405 406 Args: 407 key: Key to remove. 408 409 Example:: 410 411 m = TreeMap([[1, "A"], [2, "B"], [3, "C"]]) 412 m.popitem(2) # "(2,B)", m is now {1:A,3:C} 413 m.popitem(9) # raises KeyError 414 415 """ 416 iter = self.find(key) 417 if not iter.equals(self.end()): 418 k = iter.key 419 v = iter.value 420 self.erase(iter) 421 return (k, v) 422 raise KeyError(f"Key {key} not found")
Remove key and return its first key-value tuple or raise KeyError.
Args: key: Key to remove.
Example::
m = TreeMap([[1, "A"], [2, "B"], [3, "C"]])
m.popitem(2) # "(2,B)", m is now {1:A,3:C}
m.popitem(9) # raises KeyError
428 def backwards(self) -> PyReverseIterator[K]: 429 """ 430 Return a reverse iterator over keys in descending key order (including duplicates). 431 432 Example:: 433 434 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 435 for key in m.backwards(): 436 print(key) 437 # 2 438 # 2 439 # 1 440 441 """ 442 return self._t.keys().backwards()
Return a reverse iterator over keys in descending key order (including duplicates).
Example::
m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]])
for key in m.backwards():
print(key)
# 2
# 2
# 1
481 def begin(self) -> TreeIterator[K, V]: 482 """ 483 Return a forward STL-like iterator to the first entry. 484 485 Example:: 486 487 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 488 it = m.begin() 489 while not it.equals(m.end()): 490 print(f"key: {it.key}, value: {it.value}") 491 it.next() 492 # key: 1, value: A 493 # key: 2, value: B 494 # key: 2, value: C 495 496 """ 497 return self._t.begin()
Return a forward STL-like iterator to the first entry.
Example::
m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]])
it = m.begin()
while not it.equals(m.end()):
print(f"key: {it.key}, value: {it.value}")
it.next()
# key: 1, value: A
# key: 2, value: B
# key: 2, value: C
499 def end(self) -> TreeIterator[K, V]: 500 """ 501 Return a forward STL-like iterator past the last entry. 502 503 Example:: 504 505 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 506 it = m.begin() 507 while not it.equals(m.end()): 508 print(f"key: {it.key}, value: {it.value}") 509 it.next() 510 511 """ 512 return self._t.end()
Return a forward STL-like iterator past the last entry.
Example::
m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]])
it = m.begin()
while not it.equals(m.end()):
print(f"key: {it.key}, value: {it.value}")
it.next()
514 def find(self, key: K) -> TreeIterator[K, V]: 515 """ 516 Return a forward iterator to the first entry with *key*, or end() if absent. 517 518 When multiple entries share the same key, the iterator points to the first one. 519 Use lower_bound() / upper_bound() to iterate over all entries with that key. 520 521 Example:: 522 523 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 524 it = m.find(2) 525 if not it.equals(m.end()): 526 print(f"key: {it.key}, value: {it.value}") # key: 2, value: B 527 m.find(99).equals(m.end()) # True 528 529 """ 530 return self._t.find(key)
Return a forward iterator to the first entry with key, or end() if absent.
When multiple entries share the same key, the iterator points to the first one. Use lower_bound() / upper_bound() to iterate over all entries with that key.
Example::
m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]])
it = m.find(2)
if not it.equals(m.end()):
print(f"key: {it.key}, value: {it.value}") # key: 2, value: B
m.find(99).equals(m.end()) # True
532 def insert_unique(self, key: K, value: V) -> InsertionResult[TreeIterator[K, V]]: 533 """ 534 Insert *(key, value)* only when *key* is not already present. 535 536 Returns: 537 InsertionResult with was_added=True when the key was new; 538 was_added=False when any entry with that key already existed. 539 540 Example:: 541 542 m = TreeMultiMap() 543 res = m.insert_unique(1, "A") 544 res.was_added # True 545 res2 = m.insert_unique(1, "B") 546 res2.was_added # False — key 1 already exists 547 548 """ 549 n: TreeNode[K, V] = TreeNode() 550 n.key = key 551 n.value = value 552 return self._t.insert_unique(n)
Insert (key, value) only when key is not already present.
Returns: InsertionResult with was_added=True when the key was new; was_added=False when any entry with that key already existed.
Example::
m = TreeMultiMap()
res = m.insert_unique(1, "A")
res.was_added # True
res2 = m.insert_unique(1, "B")
res2.was_added # False — key 1 already exists
554 def insert_or_replace(self, key: K, value: V) -> InsertionResult[TreeIterator[K, V]]: 555 """ 556 Insert *(key, value)*, replacing the first existing entry when *key* already exists. 557 558 Returns: 559 InsertionResult with was_added=True on new insertion, or 560 was_replaced=True and the updated iterator on replacement. 561 562 Example:: 563 564 m = TreeMultiMap() 565 res = m.insert_or_replace(1, "A") 566 res.was_added # True 567 res2 = m.insert_or_replace(1, "B") 568 res2.was_replaced # True 569 res2.iterator.value # "B" 570 571 """ 572 n: TreeNode[K, V] = TreeNode() 573 n.key = key 574 n.value = value 575 return self._t.insert_or_replace(n)
Insert (key, value), replacing the first existing entry when key already exists.
Returns: InsertionResult with was_added=True on new insertion, or was_replaced=True and the updated iterator on replacement.
Example::
m = TreeMultiMap()
res = m.insert_or_replace(1, "A")
res.was_added # True
res2 = m.insert_or_replace(1, "B")
res2.was_replaced # True
res2.iterator.value # "B"
577 def insert_multi(self, key: K, value: V) -> InsertionResult[TreeIterator[K, V]]: 578 """ 579 Insert *(key, value)* unconditionally, always creating a new entry. 580 581 This is the multi-key insertion that makes TreeMultiMap distinct from TreeMap. 582 583 Returns: 584 InsertionResult with was_added=True and an iterator to the new entry. 585 586 Example:: 587 588 m = TreeMultiMap() 589 res = m.insert_multi(1, "A") 590 res.was_added # True 591 res2 = m.insert_multi(1, "B") 592 res2.was_added # True — second entry with key 1 added 593 res2.iterator.prev() 594 res2.iterator.value # "A" 595 596 """ 597 n: TreeNode[K, V] = TreeNode() 598 n.key = key 599 n.value = value 600 return self._t.insert_multi(n)
Insert (key, value) unconditionally, always creating a new entry.
This is the multi-key insertion that makes TreeMultiMap distinct from TreeMap.
Returns: InsertionResult with was_added=True and an iterator to the new entry.
Example::
m = TreeMultiMap()
res = m.insert_multi(1, "A")
res.was_added # True
res2 = m.insert_multi(1, "B")
res2.was_added # True — second entry with key 1 added
res2.iterator.prev()
res2.iterator.value # "A"
602 def erase(self, iterator: TreeIterator[K, V]) -> None: 603 """ 604 Remove the entry pointed to by *iterator*. 605 606 Example:: 607 608 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 609 it = m.find(2) 610 m.erase(it) 611 str(m) # "{1:A,2:C}" 612 613 """ 614 self._t.erase(iterator.node)
Remove the entry pointed to by iterator.
Example::
m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]])
it = m.find(2)
m.erase(it)
str(m) # "{1:A,2:C}"
616 def lower_bound(self, key: K) -> TreeIterator[K, V]: 617 """ 618 Return an STL-like iterator to the first entry with key >= *key*, or end(). 619 620 Combined with upper_bound(), this gives a half-open range over all 621 entries that share the same key. 622 623 Example:: 624 625 m = TreeMultiMap([[2, "B1"], [2, "B2"], [4, "D"]]) 626 lo = m.lower_bound(2) 627 hi = m.upper_bound(2) 628 it = lo 629 while not it.equals(hi): 630 print(it.value) # B1, B2 631 it.next() 632 633 """ 634 return self._t.lower_bound(key)
Return an STL-like iterator to the first entry with key >= key, or end().
Combined with upper_bound(), this gives a half-open range over all entries that share the same key.
Example::
m = TreeMultiMap([[2, "B1"], [2, "B2"], [4, "D"]])
lo = m.lower_bound(2)
hi = m.upper_bound(2)
it = lo
while not it.equals(hi):
print(it.value) # B1, B2
it.next()
636 def rbegin(self) -> ReverseIterator[K, V]: 637 """ 638 Return a reverse STL-like iterator to the entry with the largest key. 639 640 Example:: 641 642 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 643 it = m.rbegin() 644 while not it.equals(m.rend()): 645 print(f"key: {it.key}, value: {it.value}") 646 it.next() 647 # key: 2, value: C 648 # key: 2, value: B 649 # key: 1, value: A 650 651 """ 652 return self._t.rbegin()
Return a reverse STL-like iterator to the entry with the largest key.
Example::
m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]])
it = m.rbegin()
while not it.equals(m.rend()):
print(f"key: {it.key}, value: {it.value}")
it.next()
# key: 2, value: C
# key: 2, value: B
# key: 1, value: A
654 def rend(self) -> ReverseIterator[K, V]: 655 """ 656 Return a reverse STL-like iterator before the entry with the smallest key. 657 658 Example:: 659 660 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 661 it = m.rbegin() 662 while not it.equals(m.rend()): 663 print(f"key: {it.key}, value: {it.value}") 664 it.next() 665 666 """ 667 return self._t.rend()
Return a reverse STL-like iterator before the entry with the smallest key.
Example::
m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]])
it = m.rbegin()
while not it.equals(m.rend()):
print(f"key: {it.key}, value: {it.value}")
it.next()
669 def upper_bound(self, key: K) -> TreeIterator[K, V]: 670 """ 671 Return an STL-like iterator to the first entry with key > *key*, or end(). 672 673 Combined with lower_bound(), this gives a half-open range over all 674 entries that share the same key. 675 676 Example:: 677 678 m = TreeMultiMap([[2, "B1"], [2, "B2"], [4, "D"]]) 679 lo = m.lower_bound(2) 680 hi = m.upper_bound(2) 681 it = lo 682 while not it.equals(hi): 683 print(it.value) # B1, B2 684 it.next() 685 686 """ 687 return self._t.upper_bound(key)
Return an STL-like iterator to the first entry with key > key, or end().
Combined with lower_bound(), this gives a half-open range over all entries that share the same key.
Example::
m = TreeMultiMap([[2, "B1"], [2, "B2"], [4, "D"]])
lo = m.lower_bound(2)
hi = m.upper_bound(2)
it = lo
while not it.equals(hi):
print(it.value) # B1, B2
it.next()
689 def first(self) -> tuple[K, V] | None: 690 """ 691 Return the first (key, value) pair, or None when the map is empty. 692 693 Example:: 694 695 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 696 key, value = m.first() # (1, "A") 697 TreeMultiMap().first() # None 698 699 """ 700 return self._t.first()
Return the first (key, value) pair, or None when the map is empty.
Example::
m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]])
key, value = m.first() # (1, "A")
TreeMultiMap().first() # None
702 def last(self) -> tuple[K, V] | None: 703 """ 704 Return the last (key, value) pair, or None when the map is empty. 705 706 Example:: 707 708 m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]]) 709 key, value = m.last() # (2, "C") 710 TreeMultiMap().last() # None 711 712 """ 713 return self._t.last()
Return the last (key, value) pair, or None when the map is empty.
Example::
m = TreeMultiMap([[1, "A"], [2, "B"], [2, "C"]])
key, value = m.last() # (2, "C")
TreeMultiMap().last() # None