diff --git a/linq/core/collections.py b/linq/core/collections.py index d4dc8af..03e84e1 100644 --- a/linq/core/collections.py +++ b/linq/core/collections.py @@ -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 diff --git a/linq/standard/general.py b/linq/standard/general.py index ef4c6b9..1276d0c 100644 --- a/linq/standard/general.py +++ b/linq/standard/general.py @@ -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 @@ -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 diff --git a/linq/standard/generator.py b/linq/standard/generator.py index 6f572ca..7bc14ad 100644 --- a/linq/standard/generator.py +++ b/linq/standard/generator.py @@ -1,3 +1,4 @@ +from ..core.collections import * from ..core.flow import * from sys import version_info diff --git a/test_manual.py b/test_manual.py index 8b6fec1..29ba324 100644 --- a/test_manual.py +++ b/test_manual.py @@ -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 @@ -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__() @@ -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() @@ -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: """ @@ -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] \ No newline at end of file