Skip to content

Iterator utilities

Iterator utilities for Result.

collect(iterable)

Collect an iterable of Result values into Ok[list].

Returns the first Err encountered, short-circuiting the iteration.

Examples:

>>> collect([Ok(1), Ok(2), Ok(3)])
Ok([1, 2, 3])
>>> collect([Ok(1), Err("bad"), Ok(3)])
Err('bad')
Source code in src/corrode/iterator.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
def collect(iterable: Iterable[Result[T, E]]) -> Result[list[T], E]:
    """
    Collect an iterable of ``Result`` values into ``Ok[list]``.

    Returns the first ``Err`` encountered, short-circuiting the iteration.

    Examples:
        >>> collect([Ok(1), Ok(2), Ok(3)])
        Ok([1, 2, 3])
        >>> collect([Ok(1), Err("bad"), Ok(3)])
        Err('bad')

    """
    items: list[T] = []
    for result in iterable:
        match result:
            case Ok(value):
                items.append(value)
            case Err():
                return result
    return Ok(items)

collect_all(iterable)

Collect an iterable of Result values, accumulating all errors.

Returns Ok of all success values only if every result is Ok; otherwise returns Err of every error encountered. Unlike collect, never short-circuits — the whole iterable is consumed, so the caller gets a complete error report (the validation use case). Unlike partition, the outcome is a Result: "all succeeded" and "something failed" are distinct variants instead of an empty-list check.

Examples:

>>> collect_all([Ok(1), Ok(2), Ok(3)])
Ok([1, 2, 3])
>>> collect_all([Ok(1), Err("a"), Ok(3), Err("b")])
Err(['a', 'b'])
Source code in src/corrode/iterator.py
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
def collect_all(iterable: Iterable[Result[T, E]]) -> Result[list[T], list[E]]:
    """
    Collect an iterable of ``Result`` values, accumulating **all** errors.

    Returns ``Ok`` of all success values only if every result is ``Ok``;
    otherwise returns ``Err`` of every error encountered. Unlike ``collect``,
    never short-circuits — the whole iterable is consumed, so the caller gets
    a complete error report (the validation use case). Unlike ``partition``,
    the outcome is a ``Result``: "all succeeded" and "something failed" are
    distinct variants instead of an empty-list check.

    Examples:
        >>> collect_all([Ok(1), Ok(2), Ok(3)])
        Ok([1, 2, 3])
        >>> collect_all([Ok(1), Err("a"), Ok(3), Err("b")])
        Err(['a', 'b'])

    """
    oks, errs = partition(iterable)
    if errs:
        return Err(errs)
    return Ok(oks)

map_collect(iterable, f)

Apply f to each element and collect into Ok[list].

Returns the first Err produced by f, short-circuiting the iteration.

Examples:

>>> def parse(s: str) -> Result[int, str]:
...     return Ok(int(s)) if s.isdigit() else Err(f"not a number: {s!r}")
>>> map_collect(["1", "2", "3"], parse)
Ok([1, 2, 3])
>>> map_collect(["1", "x", "3"], parse)
Err("not a number: 'x'")
Source code in src/corrode/iterator.py
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
def map_collect(
    iterable: Iterable[T],
    f: Callable[[T], Result[U, E]],
) -> Result[list[U], E]:
    """
    Apply *f* to each element and collect into ``Ok[list]``.

    Returns the first ``Err`` produced by *f*, short-circuiting the iteration.

    Examples:
        >>> def parse(s: str) -> Result[int, str]:
        ...     return Ok(int(s)) if s.isdigit() else Err(f"not a number: {s!r}")
        >>> map_collect(["1", "2", "3"], parse)
        Ok([1, 2, 3])
        >>> map_collect(["1", "x", "3"], parse)
        Err("not a number: 'x'")

    """
    items: list[U] = []
    for element in iterable:
        match f(element):
            case Ok(value):
                items.append(value)
            case Err() as err:
                return err
    return Ok(items)

partition(iterable)

Split an iterable of Result into (oks, errs).

Consumes all elements without short-circuiting.

Examples:

>>> partition([Ok(1), Err("a"), Ok(2), Err("b")])
([1, 2], ['a', 'b'])
Source code in src/corrode/iterator.py
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
def partition(
    iterable: Iterable[Result[T, E]],
) -> tuple[list[T], list[E]]:
    """
    Split an iterable of ``Result`` into ``(oks, errs)``.

    Consumes all elements without short-circuiting.

    Examples:
        >>> partition([Ok(1), Err("a"), Ok(2), Err("b")])
        ([1, 2], ['a', 'b'])

    """
    oks: list[T] = []
    errs: list[E] = []
    for result in iterable:
        match result:
            case Ok(value):
                oks.append(value)
            case Err(e):
                errs.append(e)
    return oks, errs

map_partition(iterable, f)

Apply f to each element and split the results into (oks, errs).

Consumes all elements without short-circuiting.

Examples:

>>> def parse(s: str) -> Result[int, str]:
...     return Ok(int(s)) if s.isdigit() else Err(f"not a number: {s!r}")
>>> map_partition(["1", "x", "3"], parse)
([1, 3], ["not a number: 'x'"])
Source code in src/corrode/iterator.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
def map_partition(
    iterable: Iterable[T],
    f: Callable[[T], Result[U, E]],
) -> tuple[list[U], list[E]]:
    """
    Apply *f* to each element and split the results into ``(oks, errs)``.

    Consumes all elements without short-circuiting.

    Examples:
        >>> def parse(s: str) -> Result[int, str]:
        ...     return Ok(int(s)) if s.isdigit() else Err(f"not a number: {s!r}")
        >>> map_partition(["1", "x", "3"], parse)
        ([1, 3], ["not a number: 'x'"])

    """
    return partition(f(element) for element in iterable)

filter_ok(iterable)

Yield the value from each Ok, skipping Err values.

Examples:

>>> list(filter_ok([Ok(1), Err("x"), Ok(2)]))
[1, 2]
Source code in src/corrode/iterator.py
134
135
136
137
138
139
140
141
142
143
144
145
146
def filter_ok(iterable: Iterable[Result[T, E]]) -> Iterator[T]:
    """
    Yield the value from each ``Ok``, skipping ``Err`` values.

    Examples:
        >>> list(filter_ok([Ok(1), Err("x"), Ok(2)]))
        [1, 2]

    """
    for result in iterable:
        match result:
            case Ok(value):
                yield value

filter_err(iterable)

Yield the error from each Err, skipping Ok values.

Examples:

>>> list(filter_err([Ok(1), Err("x"), Ok(2), Err("y")]))
['x', 'y']
Source code in src/corrode/iterator.py
149
150
151
152
153
154
155
156
157
158
159
160
161
def filter_err(iterable: Iterable[Result[T, E]]) -> Iterator[E]:
    """
    Yield the error from each ``Err``, skipping ``Ok`` values.

    Examples:
        >>> list(filter_err([Ok(1), Err("x"), Ok(2), Err("y")]))
        ['x', 'y']

    """
    for result in iterable:
        match result:
            case Err(e):
                yield e

try_reduce(iterable, initial, f)

Fold iterable with f, short-circuiting on Err.

Examples:

>>> def safe_add(acc: int, x: int) -> Result[int, str]:
...     return Err(f"negative value: {x}") if x < 0 else Ok(acc + x)
>>> try_reduce([1, 2, 3], 0, safe_add)
Ok(6)
>>> try_reduce([1, -1, 3], 0, safe_add)
Err('negative value: -1')
Source code in src/corrode/iterator.py
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
def try_reduce(
    iterable: Iterable[T],
    initial: U,
    f: Callable[[U, T], Result[U, E]],
) -> Result[U, E]:
    """
    Fold *iterable* with *f*, short-circuiting on ``Err``.

    Examples:
        >>> def safe_add(acc: int, x: int) -> Result[int, str]:
        ...     return Err(f"negative value: {x}") if x < 0 else Ok(acc + x)
        >>> try_reduce([1, 2, 3], 0, safe_add)
        Ok(6)
        >>> try_reduce([1, -1, 3], 0, safe_add)
        Err('negative value: -1')

    """
    acc: U = initial
    for element in iterable:
        match f(acc, element):
            case Ok(value):
                acc = value
            case Err() as err:
                return err
    return Ok(acc)