0
# Mutable Operations
1
2
Mutating operations available exclusively on Multiset instances for modifying multiset contents. These operations modify the multiset in-place and are not available on FrozenMultiset instances.
3
4
## Capabilities
5
6
### Element Addition and Removal
7
8
Add and remove individual elements with precise multiplicity control.
9
10
```python { .api }
11
def add(self, element, multiplicity: int = 1) -> None:
12
"""
13
Add an element to the multiset with specified multiplicity.
14
15
Parameters:
16
- element: Element to add (must be hashable)
17
- multiplicity: Number of times to add element (default: 1)
18
19
Raises:
20
ValueError: If multiplicity is negative
21
"""
22
23
def remove(self, element, multiplicity: Optional[int] = None) -> int:
24
"""
25
Remove element from multiset and return removed multiplicity.
26
27
Parameters:
28
- element: Element to remove
29
- multiplicity: Number to remove (default: remove all)
30
31
Returns:
32
Number of elements actually removed
33
34
Raises:
35
KeyError: If element not present in multiset
36
"""
37
38
def discard(self, element, multiplicity: Optional[int] = None) -> int:
39
"""
40
Remove element from multiset without raising error if not present.
41
42
Parameters:
43
- element: Element to remove
44
- multiplicity: Number to remove (default: remove all)
45
46
Returns:
47
Number of elements actually removed (0 if not present)
48
"""
49
50
def pop(self, element, default: int) -> int:
51
"""
52
Remove element and return its multiplicity.
53
54
Parameters:
55
- element: Element to remove
56
- default: Value to return if element not present
57
58
Returns:
59
Multiplicity of removed element or default value
60
61
Raises:
62
KeyError: If element not present and no default provided
63
"""
64
65
def clear(self) -> None:
66
"""Remove all elements from the multiset."""
67
```
68
69
**Usage Examples:**
70
71
```python
72
from multiset import Multiset
73
74
ms = Multiset('aab') # {'a': 2, 'b': 1}
75
76
# Add elements
77
ms.add('c') # Add 'c' once: {'a': 2, 'b': 1, 'c': 1}
78
ms.add('a', 3) # Add 'a' three times: {'a': 5, 'b': 1, 'c': 1}
79
80
# Remove elements
81
removed = ms.remove('a', 2) # Remove 2 'a's, returns 2: {'a': 3, 'b': 1, 'c': 1}
82
removed = ms.discard('z', 1) # Try to remove 'z', returns 0: unchanged
83
removed = ms.remove('b') # Remove all 'b's, returns 1: {'a': 3, 'c': 1}
84
85
# Pop elements
86
count = ms.pop('c') # Remove and return count of 'c': 1
87
count = ms.pop('z', 0) # Pop 'z' with provided default: returns 0
88
89
# Clear all
90
ms.clear() # Empty multiset: {}
91
```
92
93
### Direct Assignment Operations
94
95
Set element multiplicities directly using dictionary-like assignment.
96
97
```python { .api }
98
def __setitem__(self, element, multiplicity: int) -> None:
99
"""
100
Set the multiplicity of an element directly.
101
102
Parameters:
103
- element: Element to set multiplicity for
104
- multiplicity: New multiplicity (removes element if 0)
105
106
Raises:
107
ValueError: If multiplicity is negative
108
"""
109
110
def __delitem__(self, element) -> None:
111
"""
112
Remove element completely from multiset.
113
114
Parameters:
115
- element: Element to remove
116
117
Raises:
118
KeyError: If element not present
119
"""
120
121
def setdefault(self, element, default: int = 1) -> int:
122
"""
123
Get multiplicity of element, setting to default if not present.
124
125
Parameters:
126
- element: Element to get or set
127
- default: Multiplicity to set if element not present
128
129
Returns:
130
Current or newly set multiplicity
131
"""
132
```
133
134
**Usage Examples:**
135
136
```python
137
ms = Multiset('ab') # {'a': 1, 'b': 1}
138
139
# Direct assignment
140
ms['c'] = 3 # Set 'c' to multiplicity 3: {'a': 1, 'b': 1, 'c': 3}
141
ms['a'] = 5 # Change 'a' to multiplicity 5: {'a': 5, 'b': 1, 'c': 3}
142
ms['b'] = 0 # Remove 'b' by setting to 0: {'a': 5, 'c': 3}
143
144
# Delete elements
145
del ms['c'] # Remove 'c' completely: {'a': 5}
146
147
# Set with default
148
count = ms.setdefault('x', 2) # Set 'x' to 2, returns 2: {'a': 5, 'x': 2}
149
count = ms.setdefault('a', 10) # 'a' exists, returns 5: unchanged
150
```
151
152
### Bulk Update Operations
153
154
Update multiset contents from other collections with various combination strategies.
155
156
```python { .api }
157
def update(self, *others, **kwargs) -> None:
158
"""
159
Add elements from others to this multiset (sum multiplicities).
160
161
Parameters:
162
- *others: Iterables or mappings to add elements from
163
- **kwargs: Additional element-multiplicity pairs
164
"""
165
166
def union_update(self, *others) -> None:
167
"""
168
Update multiset with union of this multiset and others.
169
Takes maximum multiplicity for each element.
170
171
Parameters:
172
- *others: Iterables or mappings to union with
173
"""
174
175
def intersection_update(self, *others) -> None:
176
"""
177
Update multiset with intersection of this multiset and others.
178
Keeps only common elements with minimum multiplicities.
179
180
Parameters:
181
- *others: Iterables or mappings to intersect with
182
"""
183
184
def difference_update(self, *others) -> None:
185
"""
186
Remove elements of others from this multiset.
187
188
Parameters:
189
- *others: Iterables or mappings to subtract
190
"""
191
192
def symmetric_difference_update(self, other) -> None:
193
"""
194
Update multiset with symmetric difference.
195
196
Parameters:
197
- other: Iterable or mapping to compute symmetric difference with
198
"""
199
200
def times_update(self, factor: int) -> None:
201
"""
202
Scale all multiplicities by factor in-place.
203
204
Parameters:
205
- factor: Scaling factor (must be non-negative)
206
207
Raises:
208
ValueError: If factor is negative
209
"""
210
```
211
212
**Usage Examples:**
213
214
```python
215
ms = Multiset('aab') # {'a': 2, 'b': 1}
216
217
# Update (combine/add multiplicities)
218
ms.update('abc') # Add from string: {'a': 3, 'b': 2, 'c': 1}
219
ms.update({'x': 2, 'y': 1}) # Add from mapping: {'a': 3, 'b': 2, 'c': 1, 'x': 2, 'y': 1}
220
221
# Union update (maximum multiplicities)
222
ms2 = Multiset('aaax') # {'a': 3, 'x': 1}
223
ms.union_update(ms2) # Take max: {'a': 3, 'b': 2, 'c': 1, 'x': 2, 'y': 1}
224
225
# Intersection update (minimum multiplicities, common elements only)
226
ms.intersection_update('axyz') # Keep common: {'a': 1, 'x': 1, 'y': 1}
227
228
# Difference update (subtract)
229
ms.difference_update('ay') # Remove: {'x': 1}
230
231
# Times update (scale)
232
ms.times_update(3) # Scale by 3: {'x': 3}
233
```
234
235
### In-Place Operators
236
237
Convenient operators for in-place multiset operations.
238
239
```python { .api }
240
def __ior__(self, other) -> Multiset:
241
"""In-place union using |= operator."""
242
243
def __iand__(self, other) -> Multiset:
244
"""In-place intersection using &= operator."""
245
246
def __isub__(self, other) -> Multiset:
247
"""In-place difference using -= operator."""
248
249
def __ixor__(self, other) -> Multiset:
250
"""In-place symmetric difference using ^= operator."""
251
252
def __imul__(self, factor: int) -> Multiset:
253
"""In-place scaling using *= operator."""
254
```
255
256
**Usage Examples:**
257
258
```python
259
ms1 = Multiset('aab') # {'a': 2, 'b': 1}
260
ms2 = Multiset('abc') # {'a': 1, 'b': 1, 'c': 1}
261
262
# In-place operations using operators
263
ms1 |= ms2 # Union: {'a': 2, 'b': 1, 'c': 1}
264
ms1 &= 'ab' # Intersection: {'a': 1, 'b': 1}
265
ms1 -= 'a' # Difference: {'b': 1}
266
ms1 *= 4 # Scale: {'b': 4}
267
268
# Note: += uses update() method for combination
269
ms1 += 'bb' # Combine: {'b': 6}
270
```
271
272
### Mutable-Specific Features
273
274
Features that distinguish mutable multisets from their immutable counterparts.
275
276
**Mutability Characteristics:**
277
278
```python
279
# Mutable multisets can be modified after creation
280
ms = Multiset('abc')
281
ms.add('d') # Allowed on Multiset
282
ms['e'] = 2 # Allowed on Multiset
283
284
# Immutable multisets cannot be modified
285
frozen_ms = FrozenMultiset('abc')
286
# frozen_ms.add('d') # AttributeError: not available
287
# frozen_ms['e'] = 2 # TypeError: not supported
288
289
# Mutable multisets are not hashable
290
# hash(ms) # TypeError: unhashable type
291
hash(frozen_ms) # Works: returns hash value
292
293
# Use in sets/dicts
294
my_set = {frozen_ms} # Allowed
295
# my_set = {ms} # TypeError: unhashable type
296
```
297
298
**Thread Safety Considerations:**
299
300
```python
301
# Mutable multisets are not thread-safe
302
# Concurrent modifications require external synchronization
303
import threading
304
305
ms = Multiset()
306
lock = threading.Lock()
307
308
def safe_add(element):
309
with lock:
310
ms.add(element)
311
312
# Use FrozenMultiset for read-only sharing between threads
313
shared_ms = FrozenMultiset('abc') # Safe to share
314
```
315
316
**Performance Notes:**
317
318
```python
319
# Bulk operations are more efficient than individual operations
320
ms = Multiset()
321
322
# Efficient: single bulk operation
323
ms.update('abcdefg' * 1000)
324
325
# Less efficient: many individual operations
326
# for char in 'abcdefg' * 1000:
327
# ms.add(char)
328
329
# In-place operations modify existing multiset
330
ms = Multiset('aaa')
331
original_id = id(ms)
332
ms += 'bbb' # Modifies existing multiset
333
assert id(ms) == original_id # Same object
334
335
# Regular operations create new multisets
336
result = ms + 'ccc' # Creates new multiset
337
assert id(result) != id(ms) # Different objects
338
```