Examples

The primary class importable from this library is the Enumerable class. To query on an existing object such as lists, tuples, or generators, you pass the object to the Enumerable constructor, then invoke chained methods like this:

from types_linq import Enumerable

lst = [1, 4, 7, 9, 16]

query = Enumerable(lst).where(lambda x: x % 2 == 0).select(lambda x: x ** 2)

for x in query:
    print(x)

This will filter the list by whether the element is even, then converts each element to the square of it. The call to where and select will return immediately. Finally when the iterator of query is requested in the for loop, the element will be enumerated in the order.

It is roughly equivalent to the following code:

for x in lst:
    if x % 2 == 0:
        print(x ** 2)

or

for x in map(lambda x: x ** 2, filter(lambda x: x % 2 == 0, lst)):
    print(x)

The output will be 16 and 256 printed on newlines.

The class supports a lot more than this. The usage is simple if you know about the interfaces in .NET as this library provides almost the exact methods. It is advised to take a look at the tests to digest more in-action use cases.

More examples

Grouping and transforming lists:

from typing import NamedTuple
from types_linq import Enumerable as En


class AnswerSheet(NamedTuple):
    subject: str
    score: int
    name: str

students = ['Jacque', 'Franklin', 'Romeo']
papers = [
    AnswerSheet(subject='Calculus', score=78, name='Jacque'),
    AnswerSheet(subject='Calculus', score=98, name='Romeo'),
    AnswerSheet(subject='Algorithms', score=59, name='Romeo'),
    AnswerSheet(subject='Mechanics', score=93, name='Jacque'),
    AnswerSheet(subject='E & M', score=87, name='Jacque'),
]

query = En(students) \
    .order_by(lambda student: student) \
    .group_join(papers,
        lambda student: student,
        lambda paper: paper.name,
        lambda student, papers: {
            'student': student,
            'papers': papers.order_by(lambda paper: paper.subject) \
                .select(lambda paper: {
                    'subject': paper.subject,
                    'score': paper.score,
                }).to_list(),
            'gpa': papers.average2(lambda paper: paper.score, None),
        }
    )

for obj in query:
    print(obj)

# output:
# {'student': 'Franklin', 'papers': [], 'gpa': None}
# {'student': 'Jacque', 'papers': [{'subject': 'E & M', 'score': 87}, {'subject': 'Mechanics', 'score': 93}, {'subject': 'Calculus', 'score': 78}], 'gpa': 86.0}
# {'student': 'Romeo', 'papers': [{'subject': 'Algorithms', 'score': 59}, {'subject': 'Calculus', 'score': 98}], 'gpa': 78.5}

Working with generators:

import random
from types_linq import Enumerable as En

def toss_coins():
    while True:
        yield random.choice(('Head', 'Tail'))

times_head = En(toss_coins()).take(5) \  # [:5] also works
    .count(lambda r: r == 'Head')

print(f'You tossed 5 times with {times_head} HEADs!')

# possible output:
# You tossed 5 times with 2 HEADs!

Working with stream output:

import sys, subprocess
from types_linq import Enumerable as En

proc = subprocess.Popen('kubectl logs -f my-pod', shell=True, stdout=subprocess.PIPE)
stdout = iter(proc.stdout.readline, b'')

query = En(stdout).where(lambda line: line.startswith(b'CRITICAL: ')) \
    .select(lambda line: line[10:].decode())

for line in query:
    sys.stdout.write(line)
    sys.stdout.flush()

# whatever.