Skip to content

PyoCounter

Bases: PyoMutableMapping[T, int], PyoReversible[T]


              flowchart TD
              pyochain.collections._counter.PyoCounter[PyoCounter]
              pyochain.abc._mappings.PyoMutableMapping[PyoMutableMapping]
              pyochain.abc._mappings.PyoMapping[PyoMapping]
              pyochain.abc._collection.PyoCollection[PyoCollection]
              pyochain.abc._sequences.PyoReversible[PyoReversible]
              pyochain.abc._iterable.PyoIterable[PyoIterable]
              pyochain.abc._collection.PyoContainer[PyoContainer]
              pyochain.abc._collection.PyoSized[PyoSized]
              pyochain.abc._mixins.Checkable[Checkable]
              pyochain.abc._mixins.Fluent[Fluent]
              pyochain.abc._mixins.Pipe[Pipe]
              pyochain.abc._mixins.Tap[Tap]

                              pyochain.abc._mappings.PyoMutableMapping --> pyochain.collections._counter.PyoCounter
                                pyochain.abc._mappings.PyoMapping --> pyochain.abc._mappings.PyoMutableMapping
                                pyochain.abc._collection.PyoCollection --> pyochain.abc._mappings.PyoMapping
                                pyochain.abc._iterable.PyoIterable --> pyochain.abc._collection.PyoCollection
                                pyochain.abc._mixins.Checkable --> pyochain.abc._iterable.PyoIterable
                
                pyochain.abc._mixins.Fluent --> pyochain.abc._iterable.PyoIterable
                                pyochain.abc._mixins.Pipe --> pyochain.abc._mixins.Fluent
                
                pyochain.abc._mixins.Tap --> pyochain.abc._mixins.Fluent
                


                pyochain.abc._collection.PyoContainer --> pyochain.abc._collection.PyoCollection
                                pyochain.abc._mixins.Checkable --> pyochain.abc._collection.PyoContainer
                

                pyochain.abc._collection.PyoSized --> pyochain.abc._collection.PyoCollection
                                pyochain.abc._mixins.Checkable --> pyochain.abc._collection.PyoSized
                




                pyochain.abc._sequences.PyoReversible --> pyochain.collections._counter.PyoCounter
                                pyochain.abc._iterable.PyoIterable --> pyochain.abc._sequences.PyoReversible
                                pyochain.abc._mixins.Checkable --> pyochain.abc._iterable.PyoIterable
                
                pyochain.abc._mixins.Fluent --> pyochain.abc._iterable.PyoIterable
                                pyochain.abc._mixins.Pipe --> pyochain.abc._mixins.Fluent
                
                pyochain.abc._mixins.Tap --> pyochain.abc._mixins.Fluent
                





              click pyochain.collections._counter.PyoCounter href "" "pyochain.collections._counter.PyoCounter"
              click pyochain.abc._mappings.PyoMutableMapping href "" "pyochain.abc._mappings.PyoMutableMapping"
              click pyochain.abc._mappings.PyoMapping href "" "pyochain.abc._mappings.PyoMapping"
              click pyochain.abc._collection.PyoCollection href "" "pyochain.abc._collection.PyoCollection"
              click pyochain.abc._sequences.PyoReversible href "" "pyochain.abc._sequences.PyoReversible"
              click pyochain.abc._iterable.PyoIterable href "" "pyochain.abc._iterable.PyoIterable"
              click pyochain.abc._collection.PyoContainer href "" "pyochain.abc._collection.PyoContainer"
              click pyochain.abc._collection.PyoSized href "" "pyochain.abc._collection.PyoSized"
              click pyochain.abc._mixins.Checkable href "" "pyochain.abc._mixins.Checkable"
              click pyochain.abc._mixins.Fluent href "" "pyochain.abc._mixins.Fluent"
              click pyochain.abc._mixins.Pipe href "" "pyochain.abc._mixins.Pipe"
              click pyochain.abc._mixins.Tap href "" "pyochain.abc._mixins.Tap"
            

Dict subclass for counting hashable items.

Sometimes called a bag or multiset. Elements are stored as dictionary keys and their counts are stored as dictionary values.

from pyochain.collections import PyoCounter

c = PyoCounter("abcdeabcdabcaba")  # count elements from a string

# three most common elements
assert c.most_common(3) == [("a", 5), ("b", 4), ("c", 3)]

# list all unique elements
assert c.iter().sort() == ["a", "b", "c", "d", "e"]

# list elements with repetitions
joined = c.elements().iter().sort().iter().join("")
assert joined == "aaaaabbbbcccdde"

# total of all counts
assert c.values().iter().sum() == 15
# count of letter 'a'
assert c["a"] == 5
# update counts from an iterable
for elem in "shazam":
    # by adding 1 to each element's count
    c[elem] += 1
# now there are seven 'a'
assert c["a"] == 7

# remove all 'b'
del c["b"]
# now there are zero 'b'
assert c["b"] == 0

# make another counter
d = PyoCounter("simsalabim")
# add in the second counter
c.update(d)
# now there are nine 'a'
assert c["a"] == 9

c.clear()  # empty the counter
assert c == PyoCounter()

Note: If a count is set to zero or reduced to zero, it will remain in the counter until the entry is deleted or the counter is cleared:

c = PyoCounter("aaabbc")
c["b"] -= 2  # reduce the count of 'b' by two
# 'b' is still in, but its count is zero
assert c.most_common() == [("a", 3), ("c", 1), ("b", 0)]
If given, count elements from an input iterable.

Or, initialize the count from another mapping of elements to their counts.

c = PyoCounter()  # a new, empty counter
assert c.is_empty()
c = PyoCounter("gallahad")  # a new counter from an iterable
assert c["a"] == 3
c = PyoCounter({"a": 4, "b": 2})  # a new counter from a mapping
assert c["b"] == 2

Source code in pyochain/collections/_counter.pyi
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
@final
class PyoCounter[T](PyoMutableMapping[T, int], PyoReversible[T]):
    """Dict subclass for counting hashable items.

    Sometimes called a bag or multiset.
    Elements are stored as dictionary keys and their counts
    are stored as dictionary values.

    ```python
    from pyochain.collections import PyoCounter

    c = PyoCounter("abcdeabcdabcaba")  # count elements from a string

    # three most common elements
    assert c.most_common(3) == [("a", 5), ("b", 4), ("c", 3)]

    # list all unique elements
    assert c.iter().sort() == ["a", "b", "c", "d", "e"]

    # list elements with repetitions
    joined = c.elements().iter().sort().iter().join("")
    assert joined == "aaaaabbbbcccdde"

    # total of all counts
    assert c.values().iter().sum() == 15
    # count of letter 'a'
    assert c["a"] == 5
    # update counts from an iterable
    for elem in "shazam":
        # by adding 1 to each element's count
        c[elem] += 1
    # now there are seven 'a'
    assert c["a"] == 7

    # remove all 'b'
    del c["b"]
    # now there are zero 'b'
    assert c["b"] == 0

    # make another counter
    d = PyoCounter("simsalabim")
    # add in the second counter
    c.update(d)
    # now there are nine 'a'
    assert c["a"] == 9

    c.clear()  # empty the counter
    assert c == PyoCounter()
    ```

    Note:  If a count is set to zero or reduced to zero, it will remain
    in the counter until the entry is deleted or the counter is cleared:
    ```python
    c = PyoCounter("aaabbc")
    c["b"] -= 2  # reduce the count of 'b' by two
    # 'b' is still in, but its count is zero
    assert c.most_common() == [("a", 3), ("c", 1), ("b", 0)]
    ```
    If given, count elements from an input iterable.

    Or, initialize the count from another mapping of elements to their counts.
    ```python
    c = PyoCounter()  # a new, empty counter
    assert c.is_empty()
    c = PyoCounter("gallahad")  # a new counter from an iterable
    assert c["a"] == 3
    c = PyoCounter({"a": 4, "b": 2})  # a new counter from a mapping
    assert c["b"] == 2
    ```

    """
    @overload
    def __new__(cls, /) -> Self: ...
    @overload
    def __new__(
        cls: type[PyoCounter[str]], iterable: None = None, /, **kwargs: int
    ) -> PyoCounter[str]: ...
    @overload
    def __new__(cls, mapping: SupportsKeysAndGetItem[T, int], /) -> Self: ...
    @overload
    def __new__(cls, iterable: Iterable[T], /) -> Self: ...
    @override
    def __iter__(self) -> Iterator[T]: ...
    @override
    def __len__(self) -> int: ...
    @override
    def __getitem__(self, key: T) -> int: ...
    @override
    def __setitem__(self, key: T, value: int) -> None: ...
    @override
    def __contains__(self, key: object) -> bool: ...
    def __missing__(self, key: T) -> int:
        """The count of elements not in the PyoCounter is zero.

        This is needed so that self[missing_item] does not raise `KeyError`.

        Args:
            key (T): The missing element to look up.

        Returns:
            int: The count of the missing element, which is always zero.
        """

    @override
    def __reversed__(self) -> Iterator[T]: ...
    @override
    def __reduce__(self) -> tuple[type[Self], tuple[dict[T, int]]]: ...
    @override
    def __delitem__(self, elem: T) -> None:
        """Like dict.__delitem__() but does not raise KeyError for missing values."""

    def __add__[S](self, other: PyoCounter[S]) -> PyoCounter[T | S]:
        """Add counts from two counters.

        ```python
        from pyochain.collections import PyoCounter

        added = PyoCounter("abbb") + PyoCounter("bcc")
        assert added == PyoCounter({"b": 4, "c": 2, "a": 1})
        ```

        Args:
            other (PyoCounter[S]): Another counter to add counts from.

        Returns:
            PyoCounter[T | S]: A new counter with the added counts.
        """

    def __sub__(self, other: PyoCounter[T]) -> PyoCounter[T]:
        """Subtract count, but keep only results with positive counts.

        ```python
        from pyochain.collections import PyoCounter

        subtracted = PyoCounter("abbbc") - PyoCounter("bccd")
        assert subtracted == PyoCounter({"b": 2, "a": 1})
        ```

        Args:
            other (PyoCounter[T]): Another counter to subtract counts from.

        Returns:
            PyoCounter[T]: A new counter with the subtracted counts, keeping only positive counts.
        """

    def __or__[S](self, other: PyoCounter[T]) -> PyoCounter[T]:
        """Union is the maximum of value in either of the input counters.

        ```python
        from pyochain.collections import PyoCounter

        union = PyoCounter("abbb") | PyoCounter("bcc")
        assert union == PyoCounter({"b": 3, "c": 2, "a": 1})
        ```


        Args:
            other (PyoCounter[T]): Another counter to take the union with.

        Returns:
            PyoCounter[T]: A new counter with the union of counts.
        """

    def __and__(self, other: PyoCounter[T]) -> PyoCounter[T]:
        """Intersection is the minimum of corresponding counts.

        ```python
        from pyochain.collections import PyoCounter

        union = PyoCounter("abbb") & PyoCounter("bcc")
        assert union == PyoCounter({"b": 1})
        ```

        Args:
            other (PyoCounter[T]): Another counter to take the intersection with.

        Returns:
            PyoCounter[T]: A new counter with the intersection of counts.
        """

    def __pos__(self) -> PyoCounter[T]:
        """Adds an empty counter, effectively stripping negative and zero counts.

        Returns:
            PyoCounter[T]: A new counter with only positive counts.
        """

    def __neg__(self) -> PyoCounter[T]:
        """Subtracts from an empty counter.

        Strips positive and zero counts, and flips the sign on negative counts.

        Returns:
            PyoCounter[T]: A new counter.
        """

    def __iadd__(self, other: SupportsItems[T, int]) -> Self:
        """Inplace add from another counter, keeping only positive counts.

        ```python
        from pyochain.collections import PyoCounter

        c = PyoCounter("abbb")
        c += PyoCounter("bcc")
        assert c == PyoCounter({"b": 4, "c": 2, "a": 1})
        ```

        Args:
            other (SupportsItems[T, int]): Another counter or mapping to add counts from.

        Returns:
            Self: The updated counter with the added counts.
        """

    def __isub__(self, other: SupportsItems[T, int]) -> Self:
        """Inplace subtract counter, but keep only results with positive counts.

        ```python
        from pyochain.collections import PyoCounter

        c = PyoCounter("abbbc")
        c -= PyoCounter("bccd")
        assert c == PyoCounter({"b": 2, "a": 1})
        ```

        Args:
            other (SupportsItems[T, int]): Another counter or mapping to subtract counts from.

        Returns:
            Self: The updated counter with the subtracted counts.
        """

    def __ior__(self, other: SupportsItems[T, int]) -> Self:
        """Inplace union is the maximum of value from either counter.

        ```python
        from pyochain.collections import PyoCounter

        c = PyoCounter("abbb")
        c |= PyoCounter("bcc")
        assert c == PyoCounter({"b": 3, "c": 2, "a": 1})
        ```

        Args:
            other (SupportsItems[T, int]): Another counter or mapping to take the union with.

        Returns:
            Self: The updated counter with the union of counts.

        """

    def __iand__(self, other: Mapping[T, int]) -> Self:
        """Inplace intersection is the minimum of corresponding counts.

        ```python
        from pyochain.collections import PyoCounter

        c = PyoCounter("abbb")
        c &= PyoCounter("bcc")
        assert c == PyoCounter({"b": 1})
        ```

        Args:
            other (Mapping[T, int]): Another counter or mapping to take the intersection with.

        Returns:
            Self: The updated counter with the intersection of counts.
        """

    @override
    def __eq__(self, other: object) -> bool:
        """True if all counts agree. Missing counts are treated as zero.

        Args:
            other (object): The object to compare with.

        Returns:
            bool: True if all counts agree, False otherwise. If `other` is not a PyoCounter or dict, returns NotImplemented.
        """

    @override
    def __ne__(self, other: object) -> bool:
        """True if any counts disagree. Missing counts are treated as zero.

        Args:
            other (object): The object to compare with.

        Returns:
            bool: True if any counts disagree, False otherwise. If `other` is not a PyoCounter or dict, returns NotImplemented.
        """

    def __le__(self, other: PyoCounter[Any]) -> bool:
        """True if all counts in self are a subset of those in other.

        Args:
            other (PyoCounter[Any]): The counter to compare with.

        Returns:
            bool: True if all counts in self are a subset of those in other, False otherwise.
        """

    def __lt__(self, other: PyoCounter[Any]) -> bool:
        """True if all counts in self are a proper subset of those in other.

        Args:
            other (PyoCounter[Any]): The counter to compare with.

        Returns:
            bool: True if all counts in self are a proper subset of those in other, False otherwise.
        """

    def __ge__(self, other: PyoCounter[Any]) -> bool:
        """True if all counts in self are a superset of those in other.

        Args:
            other (PyoCounter[Any]): The counter to compare with.

        Returns:
            bool: True if all counts in self are a superset of those in other, False otherwise.
        """

    def __gt__(self, other: PyoCounter[Any]) -> bool:
        """True if all counts in self are a proper superset of those in other.

        Args:
            other (PyoCounter[Any]): The counter to compare with.

        Returns:
            bool: True if all counts in self are a proper superset of those in other, False otherwise.
        """

    def __xor__[S](self, other: PyoCounter[S]) -> PyoCounter[T | S]:
        """Symmetric difference. Absolute value of count differences.

        The symmetric difference p ^ q is equivalent to:

            (p - q) | (q - p).

        For each element, symmetric difference gives the same result as:

            max(p[elem], q[elem]) - min(p[elem], q[elem])


        Args:
            other (PyoCounter[S]): The counter to compare with.

        Returns:
            PyoCounter[T | S]: A new counter with the symmetric difference of counts.

        Example:
            ```python
            from pyochain.collections import PyoCounter

            symmetric_diff = PyoCounter(a=5, b=3, c=2, d=2) ^ PyoCounter(
                a=1, b=3, c=5, e=1
            )
            assert symmetric_diff == PyoCounter({"a": 4, "c": 3, "d": 2, "e": 1})
            ```
        """

    def __ixor__(self, other: PyoCounter[T]) -> Self:
        """Inplace symmetric difference. Absolute value of count differences.

        Args:
            other (PyoCounter[T]): The counter to compare with.

        Returns:
            Self: The updated counter with the symmetric difference of counts.

        Example:
            ```python
            from pyochain.collections import PyoCounter

            c = PyoCounter(a=5, b=3, c=2, d=2)
            c ^= PyoCounter(a=1, b=3, c=5, e=1)
            assert c == PyoCounter({"a": 4, "c": 3, "d": 2, "e": 1})
            ```
        """

    @staticmethod
    def wrap[S](data: dict[S, int]) -> PyoCounter[S]: ...
    @overload
    def get(self, key: T, /) -> int | None: ...
    @overload
    def get(self, key: T, default: int, /) -> int: ...
    @overload
    def get[D](self, key: T, default: D, /) -> int | D: ...
    @override
    def get[D](self, key: T, default: D | None = None, /) -> int | D | None: ...
    @override
    def setdefault(self, key: T, default: int, /) -> int: ...
    def total(self) -> int:
        """Sum of the counts.

        Returns:
            int: The sum of all counts in the PyoCounter.
        """

    def most_common(self, n: int | None = None) -> Vec[tuple[T, int]]:
        """List the n most common elements and their counts from the most common to the least.

        ```python
        from pyochain.collections import PyoCounter

        most_commons = PyoCounter("abracadabra").most_common(3)
        assert most_commons == [("a", 5), ("b", 2), ("r", 2)]
        ```

        Args:
            n (int | None): The number of most common elements to return. If `None`, return all elements.

        Returns:
            Vec[tuple[T, int]]: A list of tuples containing the n most common elements and their counts.
        """

    def elements(self) -> PyoIterator[T]:
        """`Iterator` over elements repeating each as many times as its count.

        ```python
        from pyochain.collections import PyoCounter

        c = PyoCounter("ABCABC")
        assert c.elements().sort() == ["A", "A", "B", "B", "C", "C"]
        ```

        Knuth's example for prime factors of 1836:  2**2 * 3**3 * 17**1

        ```python
        import math

        prime_factors = PyoCounter({2: 2, 3: 3, 17: 1})
        assert math.prod(prime_factors.elements()) == 1836
        ```

        Note, if an element's count has been set to zero or is a negative
        number, elements() will ignore it.

        Returns:
            PyoIterator[T]: An iterator over elements repeating each as many times as its count.
        """

    @overload
    def update(self, iterable: None = None, /, **kwargs: int) -> None: ...
    @overload
    def update(self, iterable: Mapping[T, int], /, **kwargs: int) -> None: ...
    @overload
    def update(self, iterable: Iterable[T], /, **kwargs: int) -> None: ...
    @override
    def update(
        self, iterable: Mapping[T, int] | Iterable[T] | None = None, /, **kwargs: int
    ) -> None:
        """Like dict.update() but add counts instead of replacing them.

        Source can be an iterable, a dictionary, or another PyoCounter instance.

        Note:
            The regular dict.update() operation makes no sense here because the
            replace behavior results in some of the original untouched counts
            being mixed-in with all of the other counts for a mismash that
            doesn't have a straight-forward interpretation in most counting
            contexts.
            Instead, we implement straight-addition.
            Both the inputs and outputs are allowed to contain zero and negative counts.
        ```python
        from pyochain.collections import PyoCounter

        c = PyoCounter("which")
        c.update("witch")  # add elements from another iterable
        d = PyoCounter("watch")
        c.update(d)  # add elements from another counter
        # four 'h' in which, witch, and watch
        assert c["h"] == 4
        ```

        """

    @overload
    def subtract(self, iterable: None = None, /, **kwargs: int) -> None: ...
    @overload
    def subtract(self, mapping: Mapping[T, int], /, **kwargs: int) -> None: ...
    @overload
    def subtract(self, iterable: Iterable[T], /, **kwargs: int) -> None: ...
    def subtract(
        self, iterable: Mapping[T, int] | Iterable[T] | None = None, /, **kwargs: int
    ) -> None:
        """Like dict.update() but subtracts counts instead of replacing them.

        Counts can be reduced below zero.  Both the inputs and outputs are
        allowed to contain zero and negative counts.

        Source can be an iterable, a dictionary, or another PyoCounter instance.


        ```python
        from pyochain.collections import PyoCounter

        c = PyoCounter("which")
        c.subtract("witch")  # subtract elements from another iterable
        c.subtract(PyoCounter("watch"))  # subtract elements from another counter
        # 2 in which, minus 1 in witch, minus 1 in watch
        assert c["h"] == 0
        # 1 in which, minus 1 in witch, minus 1 in watch
        assert c["w"] == -1
        ```

        """

    def copy(self) -> Self:
        """Return a shallow copy."""

__missing__(key)

The count of elements not in the PyoCounter is zero.

This is needed so that self[missing_item] does not raise KeyError.

Parameters:

Name Type Description Default
key T

The missing element to look up.

required

Returns:

Name Type Description
int int

The count of the missing element, which is always zero.

Source code in pyochain/collections/_counter.pyi
100
101
102
103
104
105
106
107
108
109
110
def __missing__(self, key: T) -> int:
    """The count of elements not in the PyoCounter is zero.

    This is needed so that self[missing_item] does not raise `KeyError`.

    Args:
        key (T): The missing element to look up.

    Returns:
        int: The count of the missing element, which is always zero.
    """

__delitem__(elem)

Like dict.delitem() but does not raise KeyError for missing values.

Source code in pyochain/collections/_counter.pyi
116
117
118
@override
def __delitem__(self, elem: T) -> None:
    """Like dict.__delitem__() but does not raise KeyError for missing values."""

__add__(other)

Add counts from two counters.

from pyochain.collections import PyoCounter

added = PyoCounter("abbb") + PyoCounter("bcc")
assert added == PyoCounter({"b": 4, "c": 2, "a": 1})

Parameters:

Name Type Description Default
other PyoCounter[S]

Another counter to add counts from.

required

Returns:

Type Description
PyoCounter[T | S]

PyoCounter[T | S]: A new counter with the added counts.

Source code in pyochain/collections/_counter.pyi
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
def __add__[S](self, other: PyoCounter[S]) -> PyoCounter[T | S]:
    """Add counts from two counters.

    ```python
    from pyochain.collections import PyoCounter

    added = PyoCounter("abbb") + PyoCounter("bcc")
    assert added == PyoCounter({"b": 4, "c": 2, "a": 1})
    ```

    Args:
        other (PyoCounter[S]): Another counter to add counts from.

    Returns:
        PyoCounter[T | S]: A new counter with the added counts.
    """

__sub__(other)

Subtract count, but keep only results with positive counts.

from pyochain.collections import PyoCounter

subtracted = PyoCounter("abbbc") - PyoCounter("bccd")
assert subtracted == PyoCounter({"b": 2, "a": 1})

Parameters:

Name Type Description Default
other PyoCounter[T]

Another counter to subtract counts from.

required

Returns:

Type Description
PyoCounter[T]

PyoCounter[T]: A new counter with the subtracted counts, keeping only positive counts.

Source code in pyochain/collections/_counter.pyi
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
def __sub__(self, other: PyoCounter[T]) -> PyoCounter[T]:
    """Subtract count, but keep only results with positive counts.

    ```python
    from pyochain.collections import PyoCounter

    subtracted = PyoCounter("abbbc") - PyoCounter("bccd")
    assert subtracted == PyoCounter({"b": 2, "a": 1})
    ```

    Args:
        other (PyoCounter[T]): Another counter to subtract counts from.

    Returns:
        PyoCounter[T]: A new counter with the subtracted counts, keeping only positive counts.
    """

__or__(other)

Union is the maximum of value in either of the input counters.

from pyochain.collections import PyoCounter

union = PyoCounter("abbb") | PyoCounter("bcc")
assert union == PyoCounter({"b": 3, "c": 2, "a": 1})

Parameters:

Name Type Description Default
other PyoCounter[T]

Another counter to take the union with.

required

Returns:

Type Description
PyoCounter[T]

PyoCounter[T]: A new counter with the union of counts.

Source code in pyochain/collections/_counter.pyi
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
def __or__[S](self, other: PyoCounter[T]) -> PyoCounter[T]:
    """Union is the maximum of value in either of the input counters.

    ```python
    from pyochain.collections import PyoCounter

    union = PyoCounter("abbb") | PyoCounter("bcc")
    assert union == PyoCounter({"b": 3, "c": 2, "a": 1})
    ```


    Args:
        other (PyoCounter[T]): Another counter to take the union with.

    Returns:
        PyoCounter[T]: A new counter with the union of counts.
    """

__and__(other)

Intersection is the minimum of corresponding counts.

from pyochain.collections import PyoCounter

union = PyoCounter("abbb") & PyoCounter("bcc")
assert union == PyoCounter({"b": 1})

Parameters:

Name Type Description Default
other PyoCounter[T]

Another counter to take the intersection with.

required

Returns:

Type Description
PyoCounter[T]

PyoCounter[T]: A new counter with the intersection of counts.

Source code in pyochain/collections/_counter.pyi
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
def __and__(self, other: PyoCounter[T]) -> PyoCounter[T]:
    """Intersection is the minimum of corresponding counts.

    ```python
    from pyochain.collections import PyoCounter

    union = PyoCounter("abbb") & PyoCounter("bcc")
    assert union == PyoCounter({"b": 1})
    ```

    Args:
        other (PyoCounter[T]): Another counter to take the intersection with.

    Returns:
        PyoCounter[T]: A new counter with the intersection of counts.
    """

__pos__()

Adds an empty counter, effectively stripping negative and zero counts.

Returns:

Type Description
PyoCounter[T]

PyoCounter[T]: A new counter with only positive counts.

Source code in pyochain/collections/_counter.pyi
189
190
191
192
193
194
def __pos__(self) -> PyoCounter[T]:
    """Adds an empty counter, effectively stripping negative and zero counts.

    Returns:
        PyoCounter[T]: A new counter with only positive counts.
    """

__neg__()

Subtracts from an empty counter.

Strips positive and zero counts, and flips the sign on negative counts.

Returns:

Type Description
PyoCounter[T]

PyoCounter[T]: A new counter.

Source code in pyochain/collections/_counter.pyi
196
197
198
199
200
201
202
203
def __neg__(self) -> PyoCounter[T]:
    """Subtracts from an empty counter.

    Strips positive and zero counts, and flips the sign on negative counts.

    Returns:
        PyoCounter[T]: A new counter.
    """

__iadd__(other)

Inplace add from another counter, keeping only positive counts.

from pyochain.collections import PyoCounter

c = PyoCounter("abbb")
c += PyoCounter("bcc")
assert c == PyoCounter({"b": 4, "c": 2, "a": 1})

Parameters:

Name Type Description Default
other SupportsItems[T, int]

Another counter or mapping to add counts from.

required

Returns:

Name Type Description
Self Self

The updated counter with the added counts.

Source code in pyochain/collections/_counter.pyi
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
def __iadd__(self, other: SupportsItems[T, int]) -> Self:
    """Inplace add from another counter, keeping only positive counts.

    ```python
    from pyochain.collections import PyoCounter

    c = PyoCounter("abbb")
    c += PyoCounter("bcc")
    assert c == PyoCounter({"b": 4, "c": 2, "a": 1})
    ```

    Args:
        other (SupportsItems[T, int]): Another counter or mapping to add counts from.

    Returns:
        Self: The updated counter with the added counts.
    """

__isub__(other)

Inplace subtract counter, but keep only results with positive counts.

from pyochain.collections import PyoCounter

c = PyoCounter("abbbc")
c -= PyoCounter("bccd")
assert c == PyoCounter({"b": 2, "a": 1})

Parameters:

Name Type Description Default
other SupportsItems[T, int]

Another counter or mapping to subtract counts from.

required

Returns:

Name Type Description
Self Self

The updated counter with the subtracted counts.

Source code in pyochain/collections/_counter.pyi
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
def __isub__(self, other: SupportsItems[T, int]) -> Self:
    """Inplace subtract counter, but keep only results with positive counts.

    ```python
    from pyochain.collections import PyoCounter

    c = PyoCounter("abbbc")
    c -= PyoCounter("bccd")
    assert c == PyoCounter({"b": 2, "a": 1})
    ```

    Args:
        other (SupportsItems[T, int]): Another counter or mapping to subtract counts from.

    Returns:
        Self: The updated counter with the subtracted counts.
    """

__ior__(other)

Inplace union is the maximum of value from either counter.

from pyochain.collections import PyoCounter

c = PyoCounter("abbb")
c |= PyoCounter("bcc")
assert c == PyoCounter({"b": 3, "c": 2, "a": 1})

Parameters:

Name Type Description Default
other SupportsItems[T, int]

Another counter or mapping to take the union with.

required

Returns:

Name Type Description
Self Self

The updated counter with the union of counts.

Source code in pyochain/collections/_counter.pyi
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
def __ior__(self, other: SupportsItems[T, int]) -> Self:
    """Inplace union is the maximum of value from either counter.

    ```python
    from pyochain.collections import PyoCounter

    c = PyoCounter("abbb")
    c |= PyoCounter("bcc")
    assert c == PyoCounter({"b": 3, "c": 2, "a": 1})
    ```

    Args:
        other (SupportsItems[T, int]): Another counter or mapping to take the union with.

    Returns:
        Self: The updated counter with the union of counts.

    """

__iand__(other)

Inplace intersection is the minimum of corresponding counts.

from pyochain.collections import PyoCounter

c = PyoCounter("abbb")
c &= PyoCounter("bcc")
assert c == PyoCounter({"b": 1})

Parameters:

Name Type Description Default
other Mapping[T, int]

Another counter or mapping to take the intersection with.

required

Returns:

Name Type Description
Self Self

The updated counter with the intersection of counts.

Source code in pyochain/collections/_counter.pyi
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
def __iand__(self, other: Mapping[T, int]) -> Self:
    """Inplace intersection is the minimum of corresponding counts.

    ```python
    from pyochain.collections import PyoCounter

    c = PyoCounter("abbb")
    c &= PyoCounter("bcc")
    assert c == PyoCounter({"b": 1})
    ```

    Args:
        other (Mapping[T, int]): Another counter or mapping to take the intersection with.

    Returns:
        Self: The updated counter with the intersection of counts.
    """

__eq__(other)

True if all counts agree. Missing counts are treated as zero.

Parameters:

Name Type Description Default
other object

The object to compare with.

required

Returns:

Name Type Description
bool bool

True if all counts agree, False otherwise. If other is not a PyoCounter or dict, returns NotImplemented.

Source code in pyochain/collections/_counter.pyi
278
279
280
281
282
283
284
285
286
287
@override
def __eq__(self, other: object) -> bool:
    """True if all counts agree. Missing counts are treated as zero.

    Args:
        other (object): The object to compare with.

    Returns:
        bool: True if all counts agree, False otherwise. If `other` is not a PyoCounter or dict, returns NotImplemented.
    """

__ne__(other)

True if any counts disagree. Missing counts are treated as zero.

Parameters:

Name Type Description Default
other object

The object to compare with.

required

Returns:

Name Type Description
bool bool

True if any counts disagree, False otherwise. If other is not a PyoCounter or dict, returns NotImplemented.

Source code in pyochain/collections/_counter.pyi
289
290
291
292
293
294
295
296
297
298
@override
def __ne__(self, other: object) -> bool:
    """True if any counts disagree. Missing counts are treated as zero.

    Args:
        other (object): The object to compare with.

    Returns:
        bool: True if any counts disagree, False otherwise. If `other` is not a PyoCounter or dict, returns NotImplemented.
    """

__le__(other)

True if all counts in self are a subset of those in other.

Parameters:

Name Type Description Default
other PyoCounter[Any]

The counter to compare with.

required

Returns:

Name Type Description
bool bool

True if all counts in self are a subset of those in other, False otherwise.

Source code in pyochain/collections/_counter.pyi
300
301
302
303
304
305
306
307
308
def __le__(self, other: PyoCounter[Any]) -> bool:
    """True if all counts in self are a subset of those in other.

    Args:
        other (PyoCounter[Any]): The counter to compare with.

    Returns:
        bool: True if all counts in self are a subset of those in other, False otherwise.
    """

__lt__(other)

True if all counts in self are a proper subset of those in other.

Parameters:

Name Type Description Default
other PyoCounter[Any]

The counter to compare with.

required

Returns:

Name Type Description
bool bool

True if all counts in self are a proper subset of those in other, False otherwise.

Source code in pyochain/collections/_counter.pyi
310
311
312
313
314
315
316
317
318
def __lt__(self, other: PyoCounter[Any]) -> bool:
    """True if all counts in self are a proper subset of those in other.

    Args:
        other (PyoCounter[Any]): The counter to compare with.

    Returns:
        bool: True if all counts in self are a proper subset of those in other, False otherwise.
    """

__ge__(other)

True if all counts in self are a superset of those in other.

Parameters:

Name Type Description Default
other PyoCounter[Any]

The counter to compare with.

required

Returns:

Name Type Description
bool bool

True if all counts in self are a superset of those in other, False otherwise.

Source code in pyochain/collections/_counter.pyi
320
321
322
323
324
325
326
327
328
def __ge__(self, other: PyoCounter[Any]) -> bool:
    """True if all counts in self are a superset of those in other.

    Args:
        other (PyoCounter[Any]): The counter to compare with.

    Returns:
        bool: True if all counts in self are a superset of those in other, False otherwise.
    """

__gt__(other)

True if all counts in self are a proper superset of those in other.

Parameters:

Name Type Description Default
other PyoCounter[Any]

The counter to compare with.

required

Returns:

Name Type Description
bool bool

True if all counts in self are a proper superset of those in other, False otherwise.

Source code in pyochain/collections/_counter.pyi
330
331
332
333
334
335
336
337
338
def __gt__(self, other: PyoCounter[Any]) -> bool:
    """True if all counts in self are a proper superset of those in other.

    Args:
        other (PyoCounter[Any]): The counter to compare with.

    Returns:
        bool: True if all counts in self are a proper superset of those in other, False otherwise.
    """

__xor__(other)

Symmetric difference. Absolute value of count differences.

The symmetric difference p ^ q is equivalent to:

(p - q) | (q - p).

For each element, symmetric difference gives the same result as:

max(p[elem], q[elem]) - min(p[elem], q[elem])

Parameters:

Name Type Description Default
other PyoCounter[S]

The counter to compare with.

required

Returns:

Type Description
PyoCounter[T | S]

PyoCounter[T | S]: A new counter with the symmetric difference of counts.

Example
from pyochain.collections import PyoCounter

symmetric_diff = PyoCounter(a=5, b=3, c=2, d=2) ^ PyoCounter(
    a=1, b=3, c=5, e=1
)
assert symmetric_diff == PyoCounter({"a": 4, "c": 3, "d": 2, "e": 1})
Source code in pyochain/collections/_counter.pyi
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
def __xor__[S](self, other: PyoCounter[S]) -> PyoCounter[T | S]:
    """Symmetric difference. Absolute value of count differences.

    The symmetric difference p ^ q is equivalent to:

        (p - q) | (q - p).

    For each element, symmetric difference gives the same result as:

        max(p[elem], q[elem]) - min(p[elem], q[elem])


    Args:
        other (PyoCounter[S]): The counter to compare with.

    Returns:
        PyoCounter[T | S]: A new counter with the symmetric difference of counts.

    Example:
        ```python
        from pyochain.collections import PyoCounter

        symmetric_diff = PyoCounter(a=5, b=3, c=2, d=2) ^ PyoCounter(
            a=1, b=3, c=5, e=1
        )
        assert symmetric_diff == PyoCounter({"a": 4, "c": 3, "d": 2, "e": 1})
        ```
    """

__ixor__(other)

Inplace symmetric difference. Absolute value of count differences.

Parameters:

Name Type Description Default
other PyoCounter[T]

The counter to compare with.

required

Returns:

Name Type Description
Self Self

The updated counter with the symmetric difference of counts.

Example
from pyochain.collections import PyoCounter

c = PyoCounter(a=5, b=3, c=2, d=2)
c ^= PyoCounter(a=1, b=3, c=5, e=1)
assert c == PyoCounter({"a": 4, "c": 3, "d": 2, "e": 1})
Source code in pyochain/collections/_counter.pyi
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
def __ixor__(self, other: PyoCounter[T]) -> Self:
    """Inplace symmetric difference. Absolute value of count differences.

    Args:
        other (PyoCounter[T]): The counter to compare with.

    Returns:
        Self: The updated counter with the symmetric difference of counts.

    Example:
        ```python
        from pyochain.collections import PyoCounter

        c = PyoCounter(a=5, b=3, c=2, d=2)
        c ^= PyoCounter(a=1, b=3, c=5, e=1)
        assert c == PyoCounter({"a": 4, "c": 3, "d": 2, "e": 1})
        ```
    """

total()

Sum of the counts.

Returns:

Name Type Description
int int

The sum of all counts in the PyoCounter.

Source code in pyochain/collections/_counter.pyi
400
401
402
403
404
405
def total(self) -> int:
    """Sum of the counts.

    Returns:
        int: The sum of all counts in the PyoCounter.
    """

most_common(n=None)

List the n most common elements and their counts from the most common to the least.

from pyochain.collections import PyoCounter

most_commons = PyoCounter("abracadabra").most_common(3)
assert most_commons == [("a", 5), ("b", 2), ("r", 2)]

Parameters:

Name Type Description Default
n int | None

The number of most common elements to return. If None, return all elements.

None

Returns:

Type Description
Vec[tuple[T, int]]

Vec[tuple[T, int]]: A list of tuples containing the n most common elements and their counts.

Source code in pyochain/collections/_counter.pyi
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
def most_common(self, n: int | None = None) -> Vec[tuple[T, int]]:
    """List the n most common elements and their counts from the most common to the least.

    ```python
    from pyochain.collections import PyoCounter

    most_commons = PyoCounter("abracadabra").most_common(3)
    assert most_commons == [("a", 5), ("b", 2), ("r", 2)]
    ```

    Args:
        n (int | None): The number of most common elements to return. If `None`, return all elements.

    Returns:
        Vec[tuple[T, int]]: A list of tuples containing the n most common elements and their counts.
    """

elements()

Iterator over elements repeating each as many times as its count.

from pyochain.collections import PyoCounter

c = PyoCounter("ABCABC")
assert c.elements().sort() == ["A", "A", "B", "B", "C", "C"]

Knuth's example for prime factors of 1836: 22 * 33 * 17**1

import math

prime_factors = PyoCounter({2: 2, 3: 3, 17: 1})
assert math.prod(prime_factors.elements()) == 1836

Note, if an element's count has been set to zero or is a negative number, elements() will ignore it.

Returns:

Type Description
PyoIterator[T]

PyoIterator[T]: An iterator over elements repeating each as many times as its count.

Source code in pyochain/collections/_counter.pyi
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
def elements(self) -> PyoIterator[T]:
    """`Iterator` over elements repeating each as many times as its count.

    ```python
    from pyochain.collections import PyoCounter

    c = PyoCounter("ABCABC")
    assert c.elements().sort() == ["A", "A", "B", "B", "C", "C"]
    ```

    Knuth's example for prime factors of 1836:  2**2 * 3**3 * 17**1

    ```python
    import math

    prime_factors = PyoCounter({2: 2, 3: 3, 17: 1})
    assert math.prod(prime_factors.elements()) == 1836
    ```

    Note, if an element's count has been set to zero or is a negative
    number, elements() will ignore it.

    Returns:
        PyoIterator[T]: An iterator over elements repeating each as many times as its count.
    """

update(iterable=None, /, **kwargs)

update(iterable: None = None, /, **kwargs: int) -> None
update(iterable: Mapping[T, int], /, **kwargs: int) -> None
update(iterable: Iterable[T], /, **kwargs: int) -> None

Like dict.update() but add counts instead of replacing them.

Source can be an iterable, a dictionary, or another PyoCounter instance.

Note

The regular dict.update() operation makes no sense here because the replace behavior results in some of the original untouched counts being mixed-in with all of the other counts for a mismash that doesn't have a straight-forward interpretation in most counting contexts. Instead, we implement straight-addition. Both the inputs and outputs are allowed to contain zero and negative counts.

from pyochain.collections import PyoCounter

c = PyoCounter("which")
c.update("witch")  # add elements from another iterable
d = PyoCounter("watch")
c.update(d)  # add elements from another counter
# four 'h' in which, witch, and watch
assert c["h"] == 4
Source code in pyochain/collections/_counter.pyi
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
@override
def update(
    self, iterable: Mapping[T, int] | Iterable[T] | None = None, /, **kwargs: int
) -> None:
    """Like dict.update() but add counts instead of replacing them.

    Source can be an iterable, a dictionary, or another PyoCounter instance.

    Note:
        The regular dict.update() operation makes no sense here because the
        replace behavior results in some of the original untouched counts
        being mixed-in with all of the other counts for a mismash that
        doesn't have a straight-forward interpretation in most counting
        contexts.
        Instead, we implement straight-addition.
        Both the inputs and outputs are allowed to contain zero and negative counts.
    ```python
    from pyochain.collections import PyoCounter

    c = PyoCounter("which")
    c.update("witch")  # add elements from another iterable
    d = PyoCounter("watch")
    c.update(d)  # add elements from another counter
    # four 'h' in which, witch, and watch
    assert c["h"] == 4
    ```

    """

subtract(iterable=None, /, **kwargs)

subtract(iterable: None = None, /, **kwargs: int) -> None
subtract(
    mapping: Mapping[T, int], /, **kwargs: int
) -> None
subtract(iterable: Iterable[T], /, **kwargs: int) -> None

Like dict.update() but subtracts counts instead of replacing them.

Counts can be reduced below zero. Both the inputs and outputs are allowed to contain zero and negative counts.

Source can be an iterable, a dictionary, or another PyoCounter instance.

from pyochain.collections import PyoCounter

c = PyoCounter("which")
c.subtract("witch")  # subtract elements from another iterable
c.subtract(PyoCounter("watch"))  # subtract elements from another counter
# 2 in which, minus 1 in witch, minus 1 in watch
assert c["h"] == 0
# 1 in which, minus 1 in witch, minus 1 in watch
assert c["w"] == -1
Source code in pyochain/collections/_counter.pyi
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
def subtract(
    self, iterable: Mapping[T, int] | Iterable[T] | None = None, /, **kwargs: int
) -> None:
    """Like dict.update() but subtracts counts instead of replacing them.

    Counts can be reduced below zero.  Both the inputs and outputs are
    allowed to contain zero and negative counts.

    Source can be an iterable, a dictionary, or another PyoCounter instance.


    ```python
    from pyochain.collections import PyoCounter

    c = PyoCounter("which")
    c.subtract("witch")  # subtract elements from another iterable
    c.subtract(PyoCounter("watch"))  # subtract elements from another counter
    # 2 in which, minus 1 in witch, minus 1 in watch
    assert c["h"] == 0
    # 1 in which, minus 1 in witch, minus 1 in watch
    assert c["w"] == -1
    ```

    """

copy()

Return a shallow copy.

Source code in pyochain/collections/_counter.pyi
516
517
def copy(self) -> Self:
    """Return a shallow copy."""