Maps/ADT: Difference between revisions
From charlesreid1
(Overhaul: add introduction, organize operations into clear categories with tables, fix typos, expand Java section with full interface, add expected complexity table, add See also links. (via update-page on MediaWiki MCP Server)) |
(Add Python mapping protocol section alongside the existing Java Map interface section (via update-page on MediaWiki MCP Server)) |
||
| Line 126: | Line 126: | ||
Standard implementations: <code>HashMap</code> (hash table, O(1) expected), <code>TreeMap</code> (red-black tree, O(log n)), <code>LinkedHashMap</code> (hash table with insertion-order iteration). | Standard implementations: <code>HashMap</code> (hash table, O(1) expected), <code>TreeMap</code> (red-black tree, O(log n)), <code>LinkedHashMap</code> (hash table with insertion-order iteration). | ||
==Python mapping protocol== | |||
Python specifies the map ADT through two abstract base classes in <code>[https://docs.python.org/3/library/collections.abc.html collections.abc]</code>: the read-only <code>Mapping</code> and the mutable <code>MutableMapping</code> (which extends <code>Mapping</code>). The built-in <code>dict</code> type is the primary concrete implementation; user-defined map types can register as virtual subclasses or inherit directly from these ABCs. | |||
The ABC hierarchy relevant to maps: | |||
* <code>Container</code> → <code>Collection</code> → <code>Mapping</code> → <code>MutableMapping</code> | |||
* <code>Iterable</code> → <code>Collection</code> | |||
* <code>Sized</code> → <code>Collection</code> | |||
A minimal concrete <code>MutableMapping</code> must implement five abstract methods: <code>__getitem__</code>, <code>__setitem__</code>, <code>__delitem__</code>, <code>__iter__</code>, and <code>__len__</code>. All other mixin methods are derived from these five. | |||
===Core methods — <code>Mapping</code> (read-only)=== | |||
{| class="wikitable" | |||
|- | |||
! Method !! Description | |||
|- | |||
| <code>m[k]</code> (<code>__getitem__</code>) || Return the value for key <code>k</code>; raise <code>KeyError</code> if absent. ''Abstract.'' | |||
|- | |||
| <code>k '''in''' m</code> (<code>__contains__</code>) || Return <code>True</code> if key <code>k</code> is present. Default: iterate and compare. | |||
|- | |||
| <code>len(m)</code> (<code>__len__</code>) || Return the number of key-value pairs. ''Abstract.'' | |||
|- | |||
| <code>iter(m)</code> (<code>__iter__</code>) || Return an iterator over the keys. ''Abstract.'' | |||
|- | |||
| <code>m.keys()</code> || Return a <code>KeysView</code> (set-like) of all keys. | |||
|- | |||
| <code>m.values()</code> || Return a <code>ValuesView</code> of all values. | |||
|- | |||
| <code>m.items()</code> || Return an <code>ItemsView</code> (set-like) of <code>(k, v)</code> tuples. | |||
|- | |||
| <code>m.get(k, d=None)</code> || Return <code>m[k]</code> if key exists; otherwise return default <code>d</code>. | |||
|- | |||
| <code>m == m2</code> (<code>__eq__</code>) || Return <code>True</code> if both maps have the same key-value pairs. | |||
|} | |||
All views are live: they reflect changes to the underlying map. | |||
===Mutable methods — <code>MutableMapping</code>=== | |||
{| class="wikitable" | |||
|- | |||
! Method !! Description | |||
|- | |||
| <code>m[k] = v</code> (<code>__setitem__</code>) || Insert or overwrite the mapping for key <code>k</code>. ''Abstract.'' | |||
|- | |||
| <code>del m[k]</code> (<code>__delitem__</code>) || Remove the mapping for key <code>k</code>; raise <code>KeyError</code> if absent. ''Abstract.'' | |||
|- | |||
| <code>m.pop(k, d)</code> || Remove key <code>k</code> and return its value; return <code>d</code> (or raise <code>KeyError</code>) if absent. | |||
|- | |||
| <code>m.popitem()</code> || Remove and return an arbitrary <code>(k, v)</code> pair; raise <code>KeyError</code> if empty. | |||
|- | |||
| <code>m.setdefault(k, d=None)</code> || Return <code>m[k]</code> if present; otherwise set <code>m[k] = d</code> and return <code>d</code>. | |||
|- | |||
| <code>m.clear()</code> || Remove all key-value pairs. | |||
|- | |||
| <code>m.update(m2)</code> || For every <code>(k, v)</code> in <code>m2</code> (or from keyword arguments), set <code>m[k] = v</code>. | |||
|} | |||
===Dict-specific methods=== | |||
Beyond the <code>MutableMapping</code> contract, <code>dict</code> provides: | |||
{| class="wikitable" | |||
|- | |||
! Method !! Description | |||
|- | |||
| <code>dict.fromkeys(iterable, v=None)</code> || Class method: build a new dict with keys from an iterable, all mapped to value <code>v</code>. | |||
|- | |||
| <code>m.copy()</code> || Return a shallow copy of the dict. | |||
|- | |||
| <code>m {{!}} m2</code> (<code>__or__</code>) || Return a new dict merging <code>m</code> and <code>m2</code>. (Python 3.9+) | |||
|- | |||
| <code>m {{!}}= m2</code> (<code>__ior__</code>) || In-place merge: update <code>m</code> with <code>m2</code>. (Python 3.9+) | |||
|- | |||
| <code>reversed(m)</code> (<code>__reversed__</code>) || Return a reverse iterator over keys. (Python 3.8+) | |||
|} | |||
===Standard implementations=== | |||
{| class="wikitable" | |||
|- | |||
! Class !! Module !! Backing !! Notes | |||
|- | |||
| <code>dict</code> || built-in || Hash table, O(1) expected || The default mapping type. Insertion-ordered since Python 3.7. | |||
|- | |||
| <code>OrderedDict</code> || <code>collections</code> || Doubly-linked list + hash table || Remembers insertion order (present since Python 3.1; <code>dict</code> also preserves order since 3.7, but <code>OrderedDict</code> adds <code>move_to_end</code> and order-sensitive equality). | |||
|- | |||
| <code>defaultdict</code> || <code>collections</code> || Hash table || Missing keys are auto-created by a user-supplied factory function. | |||
|- | |||
| <code>Counter</code> || <code>collections</code> || Hash table || Multiset: keys map to integer counts. Supports <code>+</code>, <code>-</code>, <code>&</code>, <code>|</code> operators. | |||
|- | |||
| <code>ChainMap</code> || <code>collections</code> || Linked list of mappings || Chains multiple mappings together; lookups search each in order. | |||
|- | |||
| <code>MappingProxyType</code> || <code>types</code> || Wraps a dict || Read-only dynamic view onto another mapping. | |||
|} | |||
Python has no balanced-BST map in the standard library. Third-party packages such as [https://grantjenks.com/docs/sortedcontainers/ sortedcontainers] provide <code>SortedDict</code> with O(log n) operations. | |||
===Example: minimal custom <code>MutableMapping</code>=== | |||
<syntaxhighlight lang="python"> | |||
from collections.abc import MutableMapping | |||
class SingleEntryMap(MutableMapping): | |||
"""A map that holds at most one key-value pair.""" | |||
def __init__(self): | |||
self._key = None | |||
self._value = None | |||
def __getitem__(self, key): | |||
if self._key == key: | |||
return self._value | |||
raise KeyError(key) | |||
def __setitem__(self, key, value): | |||
self._key = key | |||
self._value = value | |||
def __delitem__(self, key): | |||
if self._key == key: | |||
self._key = None | |||
self._value = None | |||
else: | |||
raise KeyError(key) | |||
def __iter__(self): | |||
if self._key is not None: | |||
yield self._key | |||
def __len__(self): | |||
return 1 if self._key is not None else 0 | |||
def __repr__(self): | |||
return repr(dict(self)) if self._key is not None else '{}' | |||
</syntaxhighlight> | |||
Implementing the five abstract methods automatically provides <code>keys()</code>, <code>values()</code>, <code>items()</code>, <code>get()</code>, <code>pop()</code>, <code>popitem()</code>, <code>setdefault()</code>, <code>clear()</code>, <code>update()</code>, <code>__contains__</code>, and <code>__eq__</code> — all supplied by the <code>MutableMapping</code> mixin. | |||
==See also== | ==See also== | ||
Latest revision as of 04:12, 8 June 2026
The Map Abstract Data Type (ADT) defines the interface contract that all map implementations must satisfy. It specifies what operations a map supports without prescribing how they are implemented — the hallmark of an ADT. A concrete map implementation may use a hash table, a balanced tree, a sorted array, or any other suitable data structure.
A map stores key-value pairs. Each key maps to exactly one value (the map is a function from a domain of keys to a codomain of values). Keys must be unique; distinct keys may map to the same value.
Basic operations
These five operations constitute the essential interface of any map ADT:
| Operation | Pseudocode signatures | Description |
|---|---|---|
| get | m[k], m.get(k)
|
Return the value associated with key k; raise a key error if k is absent.
|
| set | m[k] = v, m.put(k, v)
|
Associate value v with key k, overwriting any previous mapping.
|
| remove | del m[k], m.remove(k)
|
Remove the entry for key k; raise a key error if absent.
|
| size | len(m), m.size()
|
Return the number of key-value pairs in the map. |
| iterate | iter(m)
|
Return an iterator over the keys of the map. |
Convenience operations
These operations can each be expressed in terms of the basic five above, but are provided for programmer convenience.
Lookup
m.contains(k)/k in m— test whether keykexists in the map; returns booleanm.get(k, d)— returnm[k]if keykexists; otherwise return default valuedm.setdefault(k, d)— if keykexists returnm[k]; otherwise setm[k] = dand returnd
Modification
m.pop(k, d)— remove keykand return its associated value; returndif key is absentm.popitem()— remove and return an arbitrary(k, v)pair; raise a key error if the map is emptym.clear()— remove all key-value pairs from the map
Views
m.keys()— return a set-like view of all keysm.values()— return a set-like view of all valuesm.items()— return a set-like view of all(k, v)tuples
Views are live: changes to the underlying map are reflected in the view, and vice versa.
Bulk operations
m.update(m2)— for every(k, v)pair in mapm2, setm[k] = vm.equals(m2)— return true if the two maps contain the same key-value pairs
Expected complexity
While the ADT itself is implementation-agnostic, useful map implementations achieve the following amortized bounds:
| Implementation | get |
put |
remove |
contains
|
|---|---|---|---|---|
| Hash table | O(1) | O(1) | O(1) | O(1) |
| Balanced BST | O(log n) | O(log n) | O(log n) | O(log n) |
| Unsorted array | O(n) | O(n) | O(n) | O(n) |
| Sorted array | O(log n) | O(n) | O(n) | O(log n) |
Java Map interface
The Java Collections Framework specifies the map ADT through the java.util.Map<K,V> interface.
Core methods
| Method | Description |
|---|---|
size() |
Return the number of key-value mappings. |
isEmpty() |
Return true if the map contains no mappings.
|
get(Object key) |
Return the value to which key is mapped, or null if absent.
|
put(K key, V value) |
Associate value with key; return the previous value, or null.
|
remove(Object key) |
Remove the mapping for key; return the previous value, or null.
|
containsKey(Object key) |
Return true if the map contains key.
|
containsValue(Object value) |
Return true if the map maps one or more keys to value.
|
keySet() |
Return a Set<K> view of the keys.
|
values() |
Return a Collection<V> view of the values.
|
entrySet() |
Return a Set<Map.Entry<K,V>> view of the entries.
|
Bulk and default methods
| Method | Description |
|---|---|
putAll(Map m) |
Copy all mappings from m into this map.
|
clear() |
Remove all mappings. |
getOrDefault(Object key, V def) |
Return value for key, or def if absent. (Java 8)
|
putIfAbsent(K key, V value) |
Insert only if key is not already present. (Java 8)
|
replace(K key, V old, V new) |
Replace value only if currently mapped to old. (Java 8)
|
computeIfAbsent(K key, Function f) |
If key is absent, compute and insert a value via f. (Java 8)
|
merge(K key, V val, BiFunction remap) |
Merge val with existing value using remap. (Java 8)
|
Standard implementations: HashMap (hash table, O(1) expected), TreeMap (red-black tree, O(log n)), LinkedHashMap (hash table with insertion-order iteration).
Python mapping protocol
Python specifies the map ADT through two abstract base classes in collections.abc: the read-only Mapping and the mutable MutableMapping (which extends Mapping). The built-in dict type is the primary concrete implementation; user-defined map types can register as virtual subclasses or inherit directly from these ABCs.
The ABC hierarchy relevant to maps:
Container→Collection→Mapping→MutableMappingIterable→CollectionSized→Collection
A minimal concrete MutableMapping must implement five abstract methods: __getitem__, __setitem__, __delitem__, __iter__, and __len__. All other mixin methods are derived from these five.
Core methods — Mapping (read-only)
| Method | Description |
|---|---|
m[k] (__getitem__) |
Return the value for key k; raise KeyError if absent. Abstract.
|
k in m (__contains__) |
Return True if key k is present. Default: iterate and compare.
|
len(m) (__len__) |
Return the number of key-value pairs. Abstract. |
iter(m) (__iter__) |
Return an iterator over the keys. Abstract. |
m.keys() |
Return a KeysView (set-like) of all keys.
|
m.values() |
Return a ValuesView of all values.
|
m.items() |
Return an ItemsView (set-like) of (k, v) tuples.
|
m.get(k, d=None) |
Return m[k] if key exists; otherwise return default d.
|
m == m2 (__eq__) |
Return True if both maps have the same key-value pairs.
|
All views are live: they reflect changes to the underlying map.
Mutable methods — MutableMapping
| Method | Description |
|---|---|
m[k] = v (__setitem__) |
Insert or overwrite the mapping for key k. Abstract.
|
del m[k] (__delitem__) |
Remove the mapping for key k; raise KeyError if absent. Abstract.
|
m.pop(k, d) |
Remove key k and return its value; return d (or raise KeyError) if absent.
|
m.popitem() |
Remove and return an arbitrary (k, v) pair; raise KeyError if empty.
|
m.setdefault(k, d=None) |
Return m[k] if present; otherwise set m[k] = d and return d.
|
m.clear() |
Remove all key-value pairs. |
m.update(m2) |
For every (k, v) in m2 (or from keyword arguments), set m[k] = v.
|
Dict-specific methods
Beyond the MutableMapping contract, dict provides:
| Method | Description |
|---|---|
dict.fromkeys(iterable, v=None) |
Class method: build a new dict with keys from an iterable, all mapped to value v.
|
m.copy() |
Return a shallow copy of the dict. |
m2 (__or__) |
Return a new dict merging m and m2. (Python 3.9+)
|
= m2 (__ior__) |
In-place merge: update m with m2. (Python 3.9+)
|
reversed(m) (__reversed__) |
Return a reverse iterator over keys. (Python 3.8+) |
Standard implementations
| Class | Module | Backing | Notes |
|---|---|---|---|
dict |
built-in | Hash table, O(1) expected | The default mapping type. Insertion-ordered since Python 3.7. |
OrderedDict |
collections |
Doubly-linked list + hash table | Remembers insertion order (present since Python 3.1; dict also preserves order since 3.7, but OrderedDict adds move_to_end and order-sensitive equality).
|
defaultdict |
collections |
Hash table | Missing keys are auto-created by a user-supplied factory function. |
Counter |
collections |
Hash table | operators. |
ChainMap |
collections |
Linked list of mappings | Chains multiple mappings together; lookups search each in order. |
MappingProxyType |
types |
Wraps a dict | Read-only dynamic view onto another mapping. |
Python has no balanced-BST map in the standard library. Third-party packages such as sortedcontainers provide SortedDict with O(log n) operations.
Example: minimal custom MutableMapping
from collections.abc import MutableMapping
class SingleEntryMap(MutableMapping):
"""A map that holds at most one key-value pair."""
def __init__(self):
self._key = None
self._value = None
def __getitem__(self, key):
if self._key == key:
return self._value
raise KeyError(key)
def __setitem__(self, key, value):
self._key = key
self._value = value
def __delitem__(self, key):
if self._key == key:
self._key = None
self._value = None
else:
raise KeyError(key)
def __iter__(self):
if self._key is not None:
yield self._key
def __len__(self):
return 1 if self._key is not None else 0
def __repr__(self):
return repr(dict(self)) if self._key is not None else '{}'
Implementing the five abstract methods automatically provides keys(), values(), items(), get(), pop(), popitem(), setdefault(), clear(), update(), __contains__, and __eq__ — all supplied by the MutableMapping mixin.
See also
- Maps — main Maps page with implementation notes
- Maps/AbstractMap — abstract base class
- Maps/UnsortedArrayMap — array-based concrete implementation
- Maps/SortedArrayMap — sorted-array concrete implementation
- Hash Maps — hash-table implementations (chaining and probing)
- Maps/Operations and Performance — timing benchmarks
| Maps and Dictionaries Part of Computer Science Notes
Series on Data Structures
Maps/Dictionaries Maps · Maps/ADT · Maps in Java · Maps/OOP · Maps/Operations and Performance Map implementations: Maps/AbstractMap · Maps/UnsortedArrayMap · Maps/SortedArrayMap Dictionary implementations: Dictionaries/LinkedDict · Dictionaries/ArrayDict
Hashes Hash Maps/OOP · Hash Maps/Operations and Performance Hash Maps/Dynamic Resizing · Hash Maps/Collision Handling with Chaining Hash functions: Hash Functions · Hash Functions/Cyclic Permutation Hash map implementations: Hash Maps/AbstractHashMap · Hash Maps/ChainedHashMap
Skip Lists · Java/ConcurrentSkipList · Java implementations: SkipList
Sets Sets · Sets/ADT · Sets in Java · Sets/OOP · Multisets
|