Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

replace generators with a deducer #5

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 39 additions & 22 deletions linq/core/collections.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,44 @@
class Generator:
def __init__(self, rule, start_elem):
self.rule = rule
self.start_elem = start_elem
class Deducer:
def __init__(self, first, rest=None):
self.first = first
self.rest = rest or (lambda: Deducer(None, None))

def __iter__(self):
now = self.start_elem
while True:
try:
yield now
now = self.rule(now)
except StopIteration:
break
@classmethod
def determine(cls, *values):
if not values:
return cls(None, None)

return cls(values[0], lambda: cls.determine(*values[1:]))

@classmethod
def deduce(cls, f, *initializer):
return cls(initializer[0], lambda: cls.deduce(f, *(initializer[1:] + (f(*initializer),))))

class ScanGenerator:
def __init__(self, rule, seq, start_elem):
self.rule = rule
self.seq = seq
self.start_elem = start_elem
@classmethod
def scan(cls, rule, seq, start_elem):
try:
iterator = iter(seq)
last = start_elem
now = rule(last, next(iterator))
return cls(now, lambda: cls.scan(rule, iterator, now))
except StopIteration:
return cls(None, None)

def __radd__(self, left):
return Deducer(left, lambda: self.determine(self.first, *self.rest()))

def __iter__(self):
last = self.start_elem
for now in self.seq:
acc = self.rule(last, now)
yield acc
last = acc
try:
if self.first is None:
raise StopIteration
yield self.first
yield from self.rest()
except StopIteration:
pass

def __next__(self):
if self.first is None:
raise StopIteration
now, nex = self.first, self.rest()
self.first, self.rest = nex.first, nex.rest
return now
6 changes: 3 additions & 3 deletions linq/standard/general.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from ..core.collections import ScanGenerator
from ..core.collections import Deducer
from ..core.flow import *
from ..core.utils import *
from functools import reduce
Expand Down Expand Up @@ -49,12 +49,12 @@ def Then(self: object, f):

@extension_std
def Scan(self: Iterable, f, start_elem):
return ScanGenerator(f, self, start_elem)
return Deducer.scan(f, self, start_elem)


@extension_std
def Reduce(self: Iterable, f, start_elem=None):
return reduce(f, self) if start_elem is None else reduce(f, self)
return reduce(f, self) if start_elem is None else reduce(f, self, start_elem)


@extension_std
Expand Down
1 change: 1 addition & 0 deletions linq/standard/generator.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from ..core.collections import *
from ..core.flow import *
from sys import version_info

Expand Down
28 changes: 23 additions & 5 deletions test_manual.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# see the standard library to get all the extension methods.

from linq.core.collections import Generator as MGenerator
from linq.core.collections import Deducer
from linq import Flow, extension_class, extension_class_name


Expand All @@ -12,7 +12,7 @@ def block_lambda(e):
else:
raise StopIteration

res = Flow(MGenerator(block_lambda, 0)).Take(100).ToList()
res = Flow(Deducer.deduce(block_lambda, 0)).Take(100).ToList()

assert res.__str__() == res.__repr__()

Expand All @@ -23,7 +23,7 @@ def block_lambda(e):
def my_test(func):
def call():
global seq
seq = Flow(MGenerator(lambda x: x + 1, start_elem=0)) # [0..\infty]
seq = Flow(Deducer.deduce(lambda x: x + 1, 0)) # [0..\infty]
func.__globals__['seq'] = seq
func()

Expand All @@ -35,8 +35,6 @@ def test_example1():
# See the definition of MGenerator at https://github.com/thautwarm/ActualFn.py/blob/master/linq/core/collections.py.
# It's a generalization of PyGenerator.
# What's more, it can be deepcopid and serialized!


"""
Example 1:
"""
Expand Down Expand Up @@ -162,3 +160,23 @@ def MyNext(self):

test_extension_byclsname()
Flow((i for i in range(10))).MyNext()


"""
Example 6:
"""
deducer_seq1 = Deducer.determine(1, 2, 3, 4, 5)
print(list(deducer_seq1))
# => [1, 2, 3, 4, 5]

deducer_seq2 = Deducer.deduce(lambda x: x + 1, 0)
print([e for (e, _) in zip(deducer_seq2, range(10))])
# => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

deducer_seq3 = Deducer.deduce(lambda x, y: x + y, 1, 1)
print([e for (e, _) in zip(deducer_seq3, range(10))])
# => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

deducer_seq4 = Deducer.scan(lambda x, y: x + y, deducer_seq2, 10)
print([e for (e, _) in zip(deducer_seq4, range(10))])
# => [10, 11, 13, 16, 20, 25, 31, 38, 46, 55]