Skip to content

PyoMutableSequence

Bases: PyoSequence[T], MutableSequence[T]

Base trait for eager pyochain mutable sequence collections.

PyoMutableSequence[T] is the shared trait for concrete, eager mutable sequence-like collections: Vec.

It extends PyoSequence[T] and collections.abc.MutableSequence[T].

This is equivalent to subclassing collections.abc.MutableSequence[T] (this trait already does), meaning any concrete subclass must implement the required MutableSequence dunder methods:

  • __getitem__
  • __setitem__
  • __delitem__
  • __len__
  • insert

On top of the standard MutableSequence protocol, it provides the additional pyochain API (from PyoSequence, PyoCollection, Pipeable, Checkable), and various methods inspired from Rust's Vec type.

Those methods provides memory-efficient in-place operations.

They are slower than simple .extend(), slices and clear() calls, but avoids all intermediate allocations, making them suitable for large collections where memory usage is a concern.

Source code in src/pyochain/traits/_iterable.py
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
class PyoMutableSequence[T](PyoSequence[T], MutableSequence[T]):
    """Base trait for eager pyochain mutable sequence collections.

    `PyoMutableSequence[T]` is the shared trait for concrete, eager mutable sequence-like
    collections: `Vec`.

    It extends `PyoSequence[T]` and `collections.abc.MutableSequence[T]`.

    This is equivalent to subclassing `collections.abc.MutableSequence[T]` (this trait
    already does), meaning any concrete subclass must implement the required
    `MutableSequence` dunder methods:

    - `__getitem__`
    - `__setitem__`
    - `__delitem__`
    - `__len__`
    - `insert`

    On top of the standard `MutableSequence` protocol, it provides the additional
    pyochain API (from `PyoSequence`, `PyoCollection`, `Pipeable`, `Checkable`), and various methods inspired from Rust's `Vec` type.

    Those methods provides memory-efficient in-place operations.

    They are slower than simple `.extend()`, slices and `clear()` calls, but avoids all intermediate allocations, making them suitable for large collections where memory usage is a concern.
    """

    __slots__ = ()

    def retain(self, predicate: Callable[[T], bool]) -> None:
        """Retains only the elements specified by the *predicate*.

        In other words, remove all elements e for which the *predicate* function returns `False`.

        This method operates in place, visiting each element exactly once in forward order, and preserves the order of the retained elements.

        Note:
            This is similar to filtering, but operates in place without allocating a new collection once collected.

            For example `new_list = list(filter(predicate, my_list))` followed by `my_list.clear()` would allocate a new collection before clearing the original, resulting in higher peak memory usage.

        Args:
            predicate (Callable[[T], bool]): A function that returns `True` for elements to keep and `False` for elements to remove.

        Examples:
        ```python
        >>> import pyochain as pc
        >>> vec = pc.Vec([1, 2, 3, 4])
        >>> vec.retain(lambda x: x % 2 == 0)
        >>> vec
        Vec(2, 4)

        ```
        External state may be used to decide which elements to keep.

        ```python
        >>> vec = pc.Vec([1, 2, 3, 4, 5])
        >>> keep = pc.Seq([False, True, True, False, True]).iter()
        >>> vec.retain(lambda _: next(keep))
        >>> vec
        Vec(2, 3, 5)

        ```
        """
        write_idx = 0
        length = len(self)
        for read_idx in range(length):
            if predicate(self[read_idx]):
                self[write_idx] = self[read_idx]
                write_idx += 1
        pop = self.pop
        while len(self) > write_idx:
            pop(write_idx)

    def truncate(self, length: int) -> None:
        """Shortens the `MutableSequence`, keeping the first *length* elements and dropping the rest.

        If *length* is greater or equal to the `MutableSequence` current `__len__()`, this has no effect.

        The `.drain()` method can emulate `.truncate()`, but causes the excess elements to be returned instead of dropped.

        Note:
            This is equivalent to `del seq[length:]`, except that it won't create an intermediate slice object.

        Args:
            length (int): The length to truncate the `MutableSequence` to.

        Examples:
        ```python
        >>> import pyochain as pc
        >>> # Truncating a five element vector to two elements:
        >>> vec = pc.Vec([1, 2, 3, 4, 5])
        >>> vec.truncate(2)
        >>> vec
        Vec(1, 2)

        ```
        No truncation occurs when len is greater than the `MutableSequence` current length:
        ```python
        >>> import pyochain as pc
        >>> vec = pc.Vec([1, 2, 3])
        >>> vec.truncate(8)
        >>> vec
        Vec(1, 2, 3)

        ```
        Truncating when len == 0 is equivalent to calling the clear method.
        ```python
        >>> import pyochain as pc
        >>> vec = pc.Vec([1, 2, 3])
        >>> vec.truncate(0)
        >>> vec
        Vec()

        ```
        """
        pop = self.pop
        for _ in range(len(self) - length):
            pop()

    def extend_move(self, other: Self | list[T]) -> None:
        """Moves all the elements of *other* into *self*, leaving *other* empty.

        Note:
            This is equivalent to `extend(other)` followed by `other.clear()`, but avoids intermediate allocations by moving elements one at a time.

        Args:
            other (Self | list[T]): The other `MutableSequence` to move elements from.

        Examples:
        ```python
        >>> import pyochain as pc
        >>> v1 = pc.Vec([1, 2, 3])
        >>> v2 = pc.Vec([4, 5, 6])
        >>> v1.extend_move(v2)
        >>> v1
        Vec(1, 2, 3, 4, 5, 6)
        >>> v2
        Vec()

        ```
        """
        pop = functools.partial(other.pop, 0)
        self.extend(pop() for _ in range(len(other)))

extend_move(other)

Moves all the elements of other into self, leaving other empty.

Note

This is equivalent to extend(other) followed by other.clear(), but avoids intermediate allocations by moving elements one at a time.

Parameters:

Name Type Description Default
other Self | list[T]

The other MutableSequence to move elements from.

required

Examples:

>>> import pyochain as pc
>>> v1 = pc.Vec([1, 2, 3])
>>> v2 = pc.Vec([4, 5, 6])
>>> v1.extend_move(v2)
>>> v1
Vec(1, 2, 3, 4, 5, 6)
>>> v2
Vec()

Source code in src/pyochain/traits/_iterable.py
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
def extend_move(self, other: Self | list[T]) -> None:
    """Moves all the elements of *other* into *self*, leaving *other* empty.

    Note:
        This is equivalent to `extend(other)` followed by `other.clear()`, but avoids intermediate allocations by moving elements one at a time.

    Args:
        other (Self | list[T]): The other `MutableSequence` to move elements from.

    Examples:
    ```python
    >>> import pyochain as pc
    >>> v1 = pc.Vec([1, 2, 3])
    >>> v2 = pc.Vec([4, 5, 6])
    >>> v1.extend_move(v2)
    >>> v1
    Vec(1, 2, 3, 4, 5, 6)
    >>> v2
    Vec()

    ```
    """
    pop = functools.partial(other.pop, 0)
    self.extend(pop() for _ in range(len(other)))

retain(predicate)

Retains only the elements specified by the predicate.

In other words, remove all elements e for which the predicate function returns False.

This method operates in place, visiting each element exactly once in forward order, and preserves the order of the retained elements.

Note

This is similar to filtering, but operates in place without allocating a new collection once collected.

For example new_list = list(filter(predicate, my_list)) followed by my_list.clear() would allocate a new collection before clearing the original, resulting in higher peak memory usage.

Parameters:

Name Type Description Default
predicate Callable[[T], bool]

A function that returns True for elements to keep and False for elements to remove.

required

Examples:

>>> import pyochain as pc
>>> vec = pc.Vec([1, 2, 3, 4])
>>> vec.retain(lambda x: x % 2 == 0)
>>> vec
Vec(2, 4)
External state may be used to decide which elements to keep.

>>> vec = pc.Vec([1, 2, 3, 4, 5])
>>> keep = pc.Seq([False, True, True, False, True]).iter()
>>> vec.retain(lambda _: next(keep))
>>> vec
Vec(2, 3, 5)
Source code in src/pyochain/traits/_iterable.py
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
def retain(self, predicate: Callable[[T], bool]) -> None:
    """Retains only the elements specified by the *predicate*.

    In other words, remove all elements e for which the *predicate* function returns `False`.

    This method operates in place, visiting each element exactly once in forward order, and preserves the order of the retained elements.

    Note:
        This is similar to filtering, but operates in place without allocating a new collection once collected.

        For example `new_list = list(filter(predicate, my_list))` followed by `my_list.clear()` would allocate a new collection before clearing the original, resulting in higher peak memory usage.

    Args:
        predicate (Callable[[T], bool]): A function that returns `True` for elements to keep and `False` for elements to remove.

    Examples:
    ```python
    >>> import pyochain as pc
    >>> vec = pc.Vec([1, 2, 3, 4])
    >>> vec.retain(lambda x: x % 2 == 0)
    >>> vec
    Vec(2, 4)

    ```
    External state may be used to decide which elements to keep.

    ```python
    >>> vec = pc.Vec([1, 2, 3, 4, 5])
    >>> keep = pc.Seq([False, True, True, False, True]).iter()
    >>> vec.retain(lambda _: next(keep))
    >>> vec
    Vec(2, 3, 5)

    ```
    """
    write_idx = 0
    length = len(self)
    for read_idx in range(length):
        if predicate(self[read_idx]):
            self[write_idx] = self[read_idx]
            write_idx += 1
    pop = self.pop
    while len(self) > write_idx:
        pop(write_idx)

truncate(length)

Shortens the MutableSequence, keeping the first length elements and dropping the rest.

If length is greater or equal to the MutableSequence current __len__(), this has no effect.

The .drain() method can emulate .truncate(), but causes the excess elements to be returned instead of dropped.

Note

This is equivalent to del seq[length:], except that it won't create an intermediate slice object.

Parameters:

Name Type Description Default
length int

The length to truncate the MutableSequence to.

required

Examples:

>>> import pyochain as pc
>>> # Truncating a five element vector to two elements:
>>> vec = pc.Vec([1, 2, 3, 4, 5])
>>> vec.truncate(2)
>>> vec
Vec(1, 2)
No truncation occurs when len is greater than the MutableSequence current length:
>>> import pyochain as pc
>>> vec = pc.Vec([1, 2, 3])
>>> vec.truncate(8)
>>> vec
Vec(1, 2, 3)
Truncating when len == 0 is equivalent to calling the clear method.
>>> import pyochain as pc
>>> vec = pc.Vec([1, 2, 3])
>>> vec.truncate(0)
>>> vec
Vec()

Source code in src/pyochain/traits/_iterable.py
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
def truncate(self, length: int) -> None:
    """Shortens the `MutableSequence`, keeping the first *length* elements and dropping the rest.

    If *length* is greater or equal to the `MutableSequence` current `__len__()`, this has no effect.

    The `.drain()` method can emulate `.truncate()`, but causes the excess elements to be returned instead of dropped.

    Note:
        This is equivalent to `del seq[length:]`, except that it won't create an intermediate slice object.

    Args:
        length (int): The length to truncate the `MutableSequence` to.

    Examples:
    ```python
    >>> import pyochain as pc
    >>> # Truncating a five element vector to two elements:
    >>> vec = pc.Vec([1, 2, 3, 4, 5])
    >>> vec.truncate(2)
    >>> vec
    Vec(1, 2)

    ```
    No truncation occurs when len is greater than the `MutableSequence` current length:
    ```python
    >>> import pyochain as pc
    >>> vec = pc.Vec([1, 2, 3])
    >>> vec.truncate(8)
    >>> vec
    Vec(1, 2, 3)

    ```
    Truncating when len == 0 is equivalent to calling the clear method.
    ```python
    >>> import pyochain as pc
    >>> vec = pc.Vec([1, 2, 3])
    >>> vec.truncate(0)
    >>> vec
    Vec()

    ```
    """
    pop = self.pop
    for _ in range(len(self) - length):
        pop()