Skip to content

Repository files navigation

Linq.py

Build StatusLicensecodecovCoverage StatusPyPI version

Install Typed-Linq

pip install -U linq-t
  • Typed-Linq = Linq + Static Checking(PyCharm performs best)
  • Linq = Auto-Completion + Readability
  • Static Checking = Safety + Debugging when coding

Additionally, static checking helps to type inference which improves the auto-completion.

Here is an example to get top 10 frequent pixels in a picture.

fromlinqimportFlowimportnumpyasnpdefmost_frequent(arr: np.ndarray) ->np.ndarray:
returnFlow(arr.flatten()) \
.group_by(None) \
.map(lambdak, v: (k, len(v))) \
.sorted(by=lambdak, count: -count)\
.take(10) \
.map(lambdak, v: k) \
.to_list() \
.then(np.array)
._# unbox

About Linq

The well-known EDSL in .NET, Language Integrated Query, in my opinion, is one of the best design in .NET environment.
Here is an example of C# Linq.

// Calculate MSE loss./// <param name="Prediction"> the prediction of the neuron network</param>/// <param name="Expected"> the expected target of the neuron network</param>Prediction.Zip(Expected,(pred,expected)=>Math.Square(pred-expected)).Average()

It's so human readable and it doesn't cost much.

And there are so many scenes very awkward to Python programmer, using Linq might help a lot.

Awkward Scenes in Python

seq1=range(100)
seq2=range(100, 200)
zipped=zip(seq1, seq2)
mapped=map(lambdaab: ab[0] /ab[1], zipped)
grouped=dict()
group_fn=lambdax: x//0.2foreinmapped:
group_id=group_fn(e)
ifgroup_idnotingrouped:
grouped[group_id] = [e]
continuegrouped[group_id].append(e)
foreingrouped.items():
print(e)

The codes seems to be too long...

Now we extract the function group_by:

defgroup_by(f, container):
grouped=dict()
foreincontainer:
group_id=f(e)
ifgroup_idnotingrouped:
grouped[group_id] = [e]
continuegrouped[group_id].append(e)
returngroupedres=group_by(lambdax: x//0.2, map(lambdaab[0]/ab[1], zip(seq1, seq2)))

Okay, it's not at fault, however, it makes me upset —— why do I have to write these ugly codes?

Now, let us try Linq!

fromlinqimportFlow, extension_stdseq=Flow(range(100))
res=seq.zip(range(100, 200)).map(lambdafst, snd : fst/snd).group_by(lambdanum: num//0.2)._

How does Linq.py work?

There is a core class object, linq.core.flow.TSource, which just has one member _.
When you want to get a specific extension method from TSource object, the type of its _ member will be used to search whether the extension method exists.
In other words, extension methods are binded with the type of _.

classTSource:
__slots__= ['_']
def__init__(self, sequence):
self._=sequencedef__getattr__(self, k):
forclsinself._.__class__.__mro__:
namespace=Extension.get(cls, '')
ifkinnamespace:
returnpartial(namespace[k], self)
where=','.join('{}.{}'.format(cls.__module__, cls.__name__) forclsinself._.__class__.__mro__)
raiseNameError("No extension method named `{}` for types `{}`.".format(k, where))
def__str__(self):
returnself._.__str__()
def__repr__(self):
returnself._.__repr__()
classFlow(Generic[T]):
def__new__(cls, seq):
returnTSource(seq)

Extension Method

Here are two methods for you to do so.

  • you can use extension_std to add extension methods for all Flow objects.

  • you use extension_class(cls) to add extension methods for all Flow objects whose member _'s type is cls.

@extension_std# For all Flow objectsdefAdd(self, i):
returnself+i@extension_class(int) # Just for type `int`defAdd(self: int, i):
returnself+iassertFlow(4).add(2)._is6

Documents of Standard Extension Methods

Note: Docs haven't been finished yet.

How to Contribute

Feel free to pull requests here.

About

Just as the name suggested.

Topics

Resources

Stars

58 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages