Skip to main content

Linqit!

Extends python's list builtin with fun, robust functionality - .NET's Language Integrated Queries (Linq) and more.
Write clean code with powerful syntax.

pip install linqit

Stop using loops, complex conditions, list comprehension and filters.
Doesn't it looks better?

from seven_dwwarfs import Grumpy, Happy, Sleepy, Bashful, Sneezy, Dopey, Doc
from linqit import List

# Go ahead and fill the list with whatever you want... like a list of <Programmer> objects.
programmers = List()
Avi = type("Avi", (), {})
elon_musk = Entrepreneur(talented=True)

# Then play:
last_hot_pizza_slice = (
    programmers.where(lambda e: e.experience > 15)
    .except_for(elon_musk)
    .of_type(Avi)
    .take(3)  # [<Avi>, <Avi>, <Avi>]
    .select(lambda avi: avi.lunch)  # [<Pizza>, <Pizza>, <Pizza>]
    .where(lambda p: p.is_hot() and p.origin != "Pizza Hut")
    .last()  # <Pizza>
    .slices.last()  # <PizzaSlice>
)

# What do you think?

We all use multiple aggregations in our code, while multiple filters/comprehensions are not pythonic at all.
The whole idea is is to use it for nested, multiple filters/modifications :).
Some of the methods might look ridiculous for a single calls, comparing to the regular python syntax.
Here are some use cases:

Methods:

all
any
concat
contains
distinct
except_for
first
get_by_attr
intersect
last
select
skip
take
where
of_type

Properties:

sum
min
max
avg
sorted

Deeper - Let's play with a list of people, a custom type.

import List

class Person():
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
        return f'Person(name="{self.name}", age={self.age})')


# Creating a list of people
avi, bill, bob, harry = Person('Avi', 23), Person('Bill', 41), Person('Bob', 77), Person('Harry', 55)

people = List(avi, bill, bob, harry)

Use LINQ selections, write cleaner code

people = people.where(lambda p: p.age > 23) # [<Person name="Bill" age="41">, <Person name="Bob" age="77">, <Person name="Harry" age="55">]
people.first()                                              # <Person name="Bill" age="41">
people.last()                                               # <Person name="Harry" age="55">
people.any(lambda p: p.name.lower().startswith('b'))        # True
people.where(age=55)                         # [<Person name="Harry" age="55">]
people.skip(3).any()                                        # False
people.skip(2).first()                                      # <Person name="Harry" age="55">

# Isn't it better than "for", "if", "else", "filter", "map" and list comprehensions in the middle of your code?

More selections

new_kids_in_town = [Person('Chris', 18), Person('Danny', 16), Person('John', 17)]
people += new_kids_in_town # Also works: people = people.concat(new_kids_in_town)

teenagers = people.where(lambda p: 20 >= p.age >= 13)
danny = teenagers.first(lambda t: t.name == 'Danny')            # <Person name="Danny" age="16">
oldest_teen = teenagers.order_by(lambda t: t.age).last()                                  # <Person name="John" age="17">

Let's make python more dynamic

names = people.name                                             # ['Avi', 'Bill', 'Bob', 'Harry', 'Chris', 'John']
ages = people.age                                               # [23, 41, 77, 55, 18, 17]
teenagers_names = teenagers.name                                # ['Chris', 'Danny', 'John']
teenagers_names.take(2).except_for(lambda n: n == 'Danny')      # ['Chris']
teenagers.age.min                                               # 16
teenagers.age.avg                                               # 17
teenagers.age.max                                               # 18

Test Coverage

➜  linqit git:(master) ✗ coverage report                    
Name                  Stmts   Miss  Cover
-----------------------------------------
linqit/__init__.py        2      0   100%
linqit/linq_list.py     101     11    89%
tests/__init__.py         0      0   100%
tests/test_list.py      203      0   100%
-----------------------------------------
TOTAL                   306     11    96%

Release files for linqit 0.1.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for linqit 0.1.5
File Size Uploaded
linqit-0.1.5.tar.gz 12.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for linqit 0.1.5
File Interpreter ABI Platform
linqit-0.1.5-py3-none-any.whl Python 3 none any Details

Total release size: 24.9 kB

Release files / linqit-0.1.5.tar.gz

Download URL linqit-0.1.5.tar.gz
Size 12.1 kB
Tags Source
SHA-256 checksum
How to use checksums
0b0cacada5d63e667af8662db4c599ec12f3dca600e24ee9bff95afc18e7dcb8
BLAKE2b-256 checksum
How to use checksums
bd9bad420050149b52f77ee01c61b1ab28005701f85c45faa6fce1b4ec7fbc51
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.9.16

Release files / linqit-0.1.5-py3-none-any.whl

Download URL linqit-0.1.5-py3-none-any.whl
Size 12.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dba8b242bc491c17928a123268e499408f3428d4bb30f140d2f1a8a64f48e4dc
BLAKE2b-256 checksum
How to use checksums
03927a1118b9d754c0191d49494f4de29debc1d2d3423b25c80fc983c9e251bf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.9.16

Release history Release notifications | RSS feed

This release

0.1.5 This release

2 release files

0.1.4

2 release files

0.1.3

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page