Skip to content

# Qwery List

Qwery List is a small library introducing a new way to use higher order functions with lists, with lazy evaluation.

### Quick comparison

#### The standard python way

    xs = ['1', '2', '3', '4']
    s = reduce(
        lambda acc, x: acc + x,
        filter(
            lambda x: x < 3,
            map(
                int,
                xs
            )
        )
        ,0
    )

#### Qwery List way

    xs = QList(['1', '2', '3', '4'])
    s = (
        xs
        .map(int)
        .filter(lambda x: x < 3)
        .fold(lambda acc, x: acc + x, 0)
    )

Chaining methods makes code much more readable and follows the natural flow of reading left to right. As a bonus you get `len()` method, so no longer will you be forced to wrapp your lists in this type of code `len(xs)` and simply call `xs.len()` (I understand it is negligibly slower but look how much nicer it looks!)

# Installation

This package is available on PyPI

    pip install qwlist

# Quick tutorial

Let's say we want to read numbers from a file and choose only the even ones. No problem at all!

    from qwlist import QList

    with open('path/to/file.txt', 'r') as file:
        qlist = QList(file.readlines())

    even = (
        qlist
        .map(int)
        .filter(lambda x: x % 2 == 0)
        .collect()
    )

Why is there this `collect` at the end? Because all operations on the QList are lazy evaluated, so in order to finally apply all the operations you need to express that.

There is also an eagerly evaluated `EagerQList` in case all the actions performed on the list should be evaluated instantaneously. This object is in the `qwlist.eager` module, but it is also possible to transform `QList` into `EagerQList` simply by calling `eager()`

    from qwlist import QList

    xs = (
        QList(range(3))
        .eager()
        .map(str)
    )
    print(xs)  # ['0', '1', '2']

EagerQList has the same methods that QList has (`filter`, `map`, `foreach`, ...) but not lazy evaluated so there is no need to call `collect` at the end.

# Examples

Making QList from an iterable

    >>> QList([1, 2, 3, 4])
    [1, 2, 3, 4]

Making QList from a generator

    >>> QList(range(3))
    [0, 1, 2]

Making a list of pairs: `int` and `str`

    >>> qlist = QList([1, 2, 3])
    >>> qlist.zip(qlist.map(str)).collect()
    [(1, '1'), (2, '2'), (3, '3')]

Summing only the even numbers

    s = (
        QList(range(10))
        .filter(lambda x: x % 2 == 0)
        .fold(lambda acc, x: acc + x, 0)
    )
    print(s)  # 20

## Side note

This syntax resembles Rust syntax:

Rust | Python
--- | ---
    let xs = vec![1, 2, 3, 4];
    let double_xs: Vec<i32> = xs
        .iter()
        .map(|&x| x * 2)
        .collect();
    println!("{double_xs:?}");
    // [2, 4, 6, 8]
    xs = QList([1, 2, 3, 4])
    double_xs = (
        xs
        .map(lambda x: x * 2)
        .collect()
    )
    print(double_xs)
    # [2, 4, 6, 8]