Skip to content

Lazy

Bases: Generic[T]

Object representing lazy evaluation of called methods.

Calling any method consumes the current Lazy object. Using the same object again may cause errors due to the draining of the generator.

Found in qwlist.Lazy

Examples:

>>> qlist = QList([1, 2, 3, 4])
>>> filtered = qlist.filter(lambda x: x < 3)
>>> mapped_str = filtered.map(str)
>>> mapped_float = filtered.map(float)
>>> print(mapped_float.qlist())  # prints [1.0, 2.0]
>>> print(mapped_str.qlist())    # prints []
Source code in src\qwlist\qwlist.py
  8
  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
class Lazy(Generic[T]):
    """
    Object representing lazy evaluation of called methods.

    Calling any method **consumes** the current `Lazy` object. **Using the same object
    again may cause errors** due to the draining of the generator.

    Found in `qwlist.Lazy`

    Examples:
        >>> qlist = QList([1, 2, 3, 4])
        >>> filtered = qlist.filter(lambda x: x < 3)
        >>> mapped_str = filtered.map(str)
        >>> mapped_float = filtered.map(float)
        >>> print(mapped_float.qlist())  # prints [1.0, 2.0]
        >>> print(mapped_str.qlist())    # prints []
    """
    def __init__(self, gen: Iterable[T]):
        """
        Args:
            gen (Iterable[T]): generator used to yield values on collecting items.
        """
        self.gen = gen

    def __repr__(self) -> str:
        return f'Lazy({repr(self.gen)})'

    def list(self) -> list[T]:
        """
        Evaluates the `Lazy` object into `list`.

        Returns: `list[T]`
        """
        return [elem for elem in self.gen]

    def qlist(self):
        """
        Evaluates the `Lazy` object into `QList`.
        Same as calling `collect()`

        Returns: `QList[T]`
        """
        return QList(elem for elem in self.gen)

    def filter(self, pred: Callable[[T], bool]):
        """
        Returns a `Lazy` object containing all values from this `Lazy` object for which
        the predicate holds true.

        Args:
            pred: `function (T) -> bool`

        Returns: `Lazy[T]`

        Examples:
            >>> Lazy([0, 1, 2, 3]).filter(lambda x: x < 2).collect()
            [0, 1]
        """
        def inner():
            for elem in self.gen:
                if pred(elem):
                    yield elem
        return Lazy(inner())

    def map(self, mapper: Callable[[T], K]):
        """
        Returns a `Lazy` object containing all values from this `Lazy` object with
        the mapping function applied on them.

        Args:
            mapper: `function: (T) -> K`

        Returns: `Lazy[K]`
        """
        def inner():
            for elem in self.gen:
                yield mapper(elem)
        return Lazy(inner())

    def fold(self, operation: Callable[[K, T], K], init: K) -> K:
        """
        Given the combination operator reduces the `Lazy` object by processing
        its constituent parts, building up the final value.

        **Other names:** fold_left, reduce, accumulate, aggregate

        Args:
            operation: `function: (K, T) -> K`. Given the initial value `init` applies the
                given combination operator on each element yielded by the Lazy object,
                treating the result as a first argument in the next step.
            init: initial value for the combination operator.

        Returns: `K`

        Examples:
            >>> Lazy([1, 2, 3]).fold(lambda acc, x: acc + x, 0)
            6
        """
        acc = init
        for elem in self.gen:
            acc = operation(acc, elem)
        return acc

    def foreach(self, action: Callable[[T], None]):
        """
        Applies the given function to each of yielded elements.

        Args:
            action: `function (T) -> None`

        Returns: `None`
        """
        for elem in self.gen:
            action(elem)

    def flatmap(self, mapper: Callable[[T], Iterable[K]]):
        """
        Applies the mapper function to each of the yielded elements and flattens the results.

        Args:
            mapper: `function (T) -> Iterable[K]`

        Returns: `Lazy[K]`

        Examples:
            >>> Lazy([1, 2]).flatmap(lambda x: [x, x]).qlist()
            [1, 1, 2, 2]
        """
        def inner():
            for elem in self.gen:
                yield from mapper(elem)
        return Lazy(inner())

    def zip(self, other: Iterable[K]) -> "Lazy[tuple[T, K]]":
        """
        Combines this `Lazy` object with the given `Iterable` elementwise as tuples.
         The returned `Lazy` objects yields at most the number of elements of
         the shorter sequence (`Lazy` or `Iterable`).

        Args:
            other: iterable to zip with this `Lazy` object.

        Returns: `Lazy[tuple[T, K]]`

        Examples:
            >>> Lazy([1, 2, 3]).zip(['a', 'b', 'c']).collect()
            [(1, 'a'), (2, 'b'), (3, 'c')]
        """
        return Lazy(zip(self.gen, other))

    def collect(self) -> "QList[T]":
        """
        Evaluates the `Lazy` object into `QList`.
        Same as calling `qlist()`

        Returns: `QList[T]`

        """
        return QList(x for x in self.gen)

    def __iter__(self):
        return iter(self.gen)

    def skip(self, n: int) -> "Lazy[T]":
        """
        Skips n first elements of the `Lazy` object.
        Args:
            n: numbers of elements to skip. Should be non-negative

        Returns: `Lazy[T]`

        Examples:
            >>> Lazy(range(10)).skip(2).collect()
            [2, 3, 4, 5, 6, 7, 8, 9]
        """
        def inner():
            for i, elem in enumerate(self.gen):
                if i >= n:
                    yield elem
        return Lazy(inner())

    def take(self, n: int) -> "Lazy[T]":
        """
        Takes n first elements of the `Lazy` object.
        Args:
            n: numbers of elements to skip. Should be non-negative

        Returns: `Lazy[T]`

        Examples:
            >>> Lazy(range(10)).take(2).collect()
            [0, 1]
        """
        def inner():
            for i, elem in enumerate(self.gen):
                if i >= n:
                    return None
                yield elem
        return Lazy(inner())

    def flatten(self) -> "Lazy[T]":
        """
        If `self` is a `Lazy` object of `Iterable[T]`, flatten concatenates all iterables into a
        single list and returns a `Lazy[T]` object.

        Returns: `Lazy[T]`

        Examples:
            >>> Lazy([[1, 2], [3, 4]]).flatten().collect()
            [1, 2, 3, 4]
        """
        def inner():
            for elem in self.gen:
                yield from elem
        return Lazy(inner())

    def cycle(self) -> "Lazy[T]":
        """
        Returns a `Lazy[T]` that cycles through the elements of the `Lazy` object, that means
        on achieving the last element the iteration starts from the beginning. The
        returned `Lazy` object has no end (infinite iterator) unless the `Lazy` object is empty
        in which case cycle returns an empty `Lazy` object (empty iterator).

        Returns: `Lazy[T]`

        Examples:
            >>> Lazy([1, 2, 3]).cycle().take(7).collect()
            [1, 2, 3, 1, 2, 3, 1]
        """
        def inner():
            saved = []
            for elem in self.gen:
                saved.append(elem)
                yield elem
            while saved:
                for elem in saved:
                    yield elem
        return Lazy(inner())

    def enumerate(self, start: int = 0) -> "Lazy[tuple[int, T]]":
        """
        Returns a `Lazy` object with index-value pairs as its elements. Index starts at
        the given position `start` (defaults to 0).

        Returns: Lazy[tuple[int, T]]

        Examples:
            >>> Lazy(['a', 'b', 'c']).enumerate().collect()
            [(0, 'a'), (1, 'b'), (2, 'c')]
        """
        def inner():
            for i, elem in enumerate(self, start=start):
                yield i, elem
        return Lazy(inner())

__init__(gen)

Parameters:

Name Type Description Default
gen Iterable[T]

generator used to yield values on collecting items.

required
Source code in src\qwlist\qwlist.py
25
26
27
28
29
30
def __init__(self, gen: Iterable[T]):
    """
    Args:
        gen (Iterable[T]): generator used to yield values on collecting items.
    """
    self.gen = gen

collect()

Evaluates the Lazy object into QList. Same as calling qlist()

Returns: QList[T]

Source code in src\qwlist\qwlist.py
158
159
160
161
162
163
164
165
166
def collect(self) -> "QList[T]":
    """
    Evaluates the `Lazy` object into `QList`.
    Same as calling `qlist()`

    Returns: `QList[T]`

    """
    return QList(x for x in self.gen)

cycle()

Returns a Lazy[T] that cycles through the elements of the Lazy object, that means on achieving the last element the iteration starts from the beginning. The returned Lazy object has no end (infinite iterator) unless the Lazy object is empty in which case cycle returns an empty Lazy object (empty iterator).

Returns: Lazy[T]

Examples:

>>> Lazy([1, 2, 3]).cycle().take(7).collect()
[1, 2, 3, 1, 2, 3, 1]
Source code in src\qwlist\qwlist.py
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
def cycle(self) -> "Lazy[T]":
    """
    Returns a `Lazy[T]` that cycles through the elements of the `Lazy` object, that means
    on achieving the last element the iteration starts from the beginning. The
    returned `Lazy` object has no end (infinite iterator) unless the `Lazy` object is empty
    in which case cycle returns an empty `Lazy` object (empty iterator).

    Returns: `Lazy[T]`

    Examples:
        >>> Lazy([1, 2, 3]).cycle().take(7).collect()
        [1, 2, 3, 1, 2, 3, 1]
    """
    def inner():
        saved = []
        for elem in self.gen:
            saved.append(elem)
            yield elem
        while saved:
            for elem in saved:
                yield elem
    return Lazy(inner())

enumerate(start=0)

Returns a Lazy object with index-value pairs as its elements. Index starts at the given position start (defaults to 0).

Returns: Lazy[tuple[int, T]]

Examples:

>>> Lazy(['a', 'b', 'c']).enumerate().collect()
[(0, 'a'), (1, 'b'), (2, 'c')]
Source code in src\qwlist\qwlist.py
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
def enumerate(self, start: int = 0) -> "Lazy[tuple[int, T]]":
    """
    Returns a `Lazy` object with index-value pairs as its elements. Index starts at
    the given position `start` (defaults to 0).

    Returns: Lazy[tuple[int, T]]

    Examples:
        >>> Lazy(['a', 'b', 'c']).enumerate().collect()
        [(0, 'a'), (1, 'b'), (2, 'c')]
    """
    def inner():
        for i, elem in enumerate(self, start=start):
            yield i, elem
    return Lazy(inner())

filter(pred)

Returns a Lazy object containing all values from this Lazy object for which the predicate holds true.

Parameters:

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

function (T) -> bool

required

Returns: Lazy[T]

Examples:

>>> Lazy([0, 1, 2, 3]).filter(lambda x: x < 2).collect()
[0, 1]
Source code in src\qwlist\qwlist.py
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
def filter(self, pred: Callable[[T], bool]):
    """
    Returns a `Lazy` object containing all values from this `Lazy` object for which
    the predicate holds true.

    Args:
        pred: `function (T) -> bool`

    Returns: `Lazy[T]`

    Examples:
        >>> Lazy([0, 1, 2, 3]).filter(lambda x: x < 2).collect()
        [0, 1]
    """
    def inner():
        for elem in self.gen:
            if pred(elem):
                yield elem
    return Lazy(inner())

flatmap(mapper)

Applies the mapper function to each of the yielded elements and flattens the results.

Parameters:

Name Type Description Default
mapper Callable[[T], Iterable[K]]

function (T) -> Iterable[K]

required

Returns: Lazy[K]

Examples:

>>> Lazy([1, 2]).flatmap(lambda x: [x, x]).qlist()
[1, 1, 2, 2]
Source code in src\qwlist\qwlist.py
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
def flatmap(self, mapper: Callable[[T], Iterable[K]]):
    """
    Applies the mapper function to each of the yielded elements and flattens the results.

    Args:
        mapper: `function (T) -> Iterable[K]`

    Returns: `Lazy[K]`

    Examples:
        >>> Lazy([1, 2]).flatmap(lambda x: [x, x]).qlist()
        [1, 1, 2, 2]
    """
    def inner():
        for elem in self.gen:
            yield from mapper(elem)
    return Lazy(inner())

flatten()

If self is a Lazy object of Iterable[T], flatten concatenates all iterables into a single list and returns a Lazy[T] object.

Returns: Lazy[T]

Examples:

>>> Lazy([[1, 2], [3, 4]]).flatten().collect()
[1, 2, 3, 4]
Source code in src\qwlist\qwlist.py
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
def flatten(self) -> "Lazy[T]":
    """
    If `self` is a `Lazy` object of `Iterable[T]`, flatten concatenates all iterables into a
    single list and returns a `Lazy[T]` object.

    Returns: `Lazy[T]`

    Examples:
        >>> Lazy([[1, 2], [3, 4]]).flatten().collect()
        [1, 2, 3, 4]
    """
    def inner():
        for elem in self.gen:
            yield from elem
    return Lazy(inner())

fold(operation, init)

Given the combination operator reduces the Lazy object by processing its constituent parts, building up the final value.

Other names: fold_left, reduce, accumulate, aggregate

Parameters:

Name Type Description Default
operation Callable[[K, T], K]

function: (K, T) -> K. Given the initial value init applies the given combination operator on each element yielded by the Lazy object, treating the result as a first argument in the next step.

required
init K

initial value for the combination operator.

required

Returns: K

Examples:

>>> Lazy([1, 2, 3]).fold(lambda acc, x: acc + x, 0)
6
Source code in src\qwlist\qwlist.py
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
def fold(self, operation: Callable[[K, T], K], init: K) -> K:
    """
    Given the combination operator reduces the `Lazy` object by processing
    its constituent parts, building up the final value.

    **Other names:** fold_left, reduce, accumulate, aggregate

    Args:
        operation: `function: (K, T) -> K`. Given the initial value `init` applies the
            given combination operator on each element yielded by the Lazy object,
            treating the result as a first argument in the next step.
        init: initial value for the combination operator.

    Returns: `K`

    Examples:
        >>> Lazy([1, 2, 3]).fold(lambda acc, x: acc + x, 0)
        6
    """
    acc = init
    for elem in self.gen:
        acc = operation(acc, elem)
    return acc

foreach(action)

Applies the given function to each of yielded elements.

Parameters:

Name Type Description Default
action Callable[[T], None]

function (T) -> None

required

Returns: None

Source code in src\qwlist\qwlist.py
111
112
113
114
115
116
117
118
119
120
121
def foreach(self, action: Callable[[T], None]):
    """
    Applies the given function to each of yielded elements.

    Args:
        action: `function (T) -> None`

    Returns: `None`
    """
    for elem in self.gen:
        action(elem)

list()

Evaluates the Lazy object into list.

Returns: list[T]

Source code in src\qwlist\qwlist.py
35
36
37
38
39
40
41
def list(self) -> list[T]:
    """
    Evaluates the `Lazy` object into `list`.

    Returns: `list[T]`
    """
    return [elem for elem in self.gen]

map(mapper)

Returns a Lazy object containing all values from this Lazy object with the mapping function applied on them.

Parameters:

Name Type Description Default
mapper Callable[[T], K]

function: (T) -> K

required

Returns: Lazy[K]

Source code in src\qwlist\qwlist.py
72
73
74
75
76
77
78
79
80
81
82
83
84
85
def map(self, mapper: Callable[[T], K]):
    """
    Returns a `Lazy` object containing all values from this `Lazy` object with
    the mapping function applied on them.

    Args:
        mapper: `function: (T) -> K`

    Returns: `Lazy[K]`
    """
    def inner():
        for elem in self.gen:
            yield mapper(elem)
    return Lazy(inner())

qlist()

Evaluates the Lazy object into QList. Same as calling collect()

Returns: QList[T]

Source code in src\qwlist\qwlist.py
43
44
45
46
47
48
49
50
def qlist(self):
    """
    Evaluates the `Lazy` object into `QList`.
    Same as calling `collect()`

    Returns: `QList[T]`
    """
    return QList(elem for elem in self.gen)

skip(n)

Skips n first elements of the Lazy object. Args: n: numbers of elements to skip. Should be non-negative

Returns: Lazy[T]

Examples:

>>> Lazy(range(10)).skip(2).collect()
[2, 3, 4, 5, 6, 7, 8, 9]
Source code in src\qwlist\qwlist.py
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
def skip(self, n: int) -> "Lazy[T]":
    """
    Skips n first elements of the `Lazy` object.
    Args:
        n: numbers of elements to skip. Should be non-negative

    Returns: `Lazy[T]`

    Examples:
        >>> Lazy(range(10)).skip(2).collect()
        [2, 3, 4, 5, 6, 7, 8, 9]
    """
    def inner():
        for i, elem in enumerate(self.gen):
            if i >= n:
                yield elem
    return Lazy(inner())

take(n)

Takes n first elements of the Lazy object. Args: n: numbers of elements to skip. Should be non-negative

Returns: Lazy[T]

Examples:

>>> Lazy(range(10)).take(2).collect()
[0, 1]
Source code in src\qwlist\qwlist.py
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
def take(self, n: int) -> "Lazy[T]":
    """
    Takes n first elements of the `Lazy` object.
    Args:
        n: numbers of elements to skip. Should be non-negative

    Returns: `Lazy[T]`

    Examples:
        >>> Lazy(range(10)).take(2).collect()
        [0, 1]
    """
    def inner():
        for i, elem in enumerate(self.gen):
            if i >= n:
                return None
            yield elem
    return Lazy(inner())

zip(other)

Combines this Lazy object with the given Iterable elementwise as tuples. The returned Lazy objects yields at most the number of elements of the shorter sequence (Lazy or Iterable).

Parameters:

Name Type Description Default
other Iterable[K]

iterable to zip with this Lazy object.

required

Returns: Lazy[tuple[T, K]]

Examples:

>>> Lazy([1, 2, 3]).zip(['a', 'b', 'c']).collect()
[(1, 'a'), (2, 'b'), (3, 'c')]
Source code in src\qwlist\qwlist.py
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
def zip(self, other: Iterable[K]) -> "Lazy[tuple[T, K]]":
    """
    Combines this `Lazy` object with the given `Iterable` elementwise as tuples.
     The returned `Lazy` objects yields at most the number of elements of
     the shorter sequence (`Lazy` or `Iterable`).

    Args:
        other: iterable to zip with this `Lazy` object.

    Returns: `Lazy[tuple[T, K]]`

    Examples:
        >>> Lazy([1, 2, 3]).zip(['a', 'b', 'c']).collect()
        [(1, 'a'), (2, 'b'), (3, 'c')]
    """
    return Lazy(zip(self.gen, other))