Lazy - Qwery List

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))