From 2c6611baf3918f6ebac0044e97364ca71417da3f Mon Sep 17 00:00:00 2001 From: Athedorer <1103713644@qq.com> Date: Tue, 26 Dec 2017 19:17:32 +0800 Subject: [PATCH 1/8] add deducer --- linq/core/collections.py | 43 +++++++++++++++++++++++++++++++++++++- linq/standard/general.py | 4 ++-- linq/standard/generator.py | 8 +++++++ test_manual.py | 31 +++++++++++++++++++++++---- 4 files changed, 79 insertions(+), 7 deletions(-) diff --git a/linq/core/collections.py b/linq/core/collections.py index d4dc8af..3c3a96d 100644 --- a/linq/core/collections.py +++ b/linq/core/collections.py @@ -1,3 +1,6 @@ +from ..core.utils import concat_generator + + class Generator: def __init__(self, rule, start_elem): self.rule = rule @@ -13,7 +16,15 @@ def __iter__(self): break -class ScanGenerator: +class Unitter(Generator): + def __init__(self, unit): + def stop(_): + raise StopIteration() + + super().__init__(stop, unit) + + +class Scanner: def __init__(self, rule, seq, start_elem): self.rule = rule self.seq = seq @@ -25,3 +36,33 @@ def __iter__(self): acc = self.rule(last, now) yield acc last = acc + + +class Deducer: + def __init__(self, first, rest=None): + self.first = first + self.rest = rest or (lambda: Deducer(None, None)) + + @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))) + + def __radd__(self, left): + return Deducer(left, lambda: self.determine(self.first, *self.rest())) + + def __iter__(self): + try: + if self.first is None: + raise StopIteration() + yield self.first + yield from self.rest() + except StopIteration: + pass diff --git a/linq/standard/general.py b/linq/standard/general.py index 823140e..2cf66e4 100644 --- a/linq/standard/general.py +++ b/linq/standard/general.py @@ -1,4 +1,4 @@ -from ..core.collections import ScanGenerator +from ..core.collections import Scanner from ..core.flow import * from ..core.utils import * from functools import reduce @@ -54,7 +54,7 @@ def Then(self: Flow, f): @extension_std def Scan(self: Flow, f, start_elem): - return Flow(ScanGenerator(f, self.stream, start_elem)) + return Flow(Scanner(f, self.stream, start_elem)) @extension_std diff --git a/linq/standard/generator.py b/linq/standard/generator.py index 62c1942..65a0891 100644 --- a/linq/standard/generator.py +++ b/linq/standard/generator.py @@ -1,4 +1,6 @@ +from ..core.collections import * from ..core.flow import * +from ..core.utils import * src = globals() __all__ = [src] @@ -7,3 +9,9 @@ @extension_class_name('generator') def Next(self: Flow): return Flow(next(self.stream)) + + +@extension_class_name('generator') +def Depend(self: Flow, elem): + head = Unitter(elem) + return Flow(concat_generator(head, self.stream)) diff --git a/test_manual.py b/test_manual.py index 252a3f8..a6143be 100644 --- a/test_manual.py +++ b/test_manual.py @@ -1,4 +1,4 @@ -from linq.core.collections import Generator as MGenerator +from linq.core.collections import Generator as MGenerator, Deducer from linq.core.flow import Flow # see the standard library to get all the extension methods. import linq.standard @@ -8,7 +8,6 @@ # It's a generalization of PyGenerator. # What's more, it can be deepcopid and serialized! - """ Example 1: """ @@ -28,7 +27,7 @@ """ Example 2: """ - +print('\n================\n') # Adding Skip to provide another semantic of Drop print(seq.Skip(10).Take(5).ToList().Unboxed()) # => [10, 11, 12, 13, 14] @@ -41,6 +40,7 @@ """ Example 3: """ +print('\n================\n') print(seq.Take(10).Reduce(lambda x, y: x + y, 10).Unboxed()) # cumulate a single result using a start value. @@ -87,7 +87,7 @@ def group_fn(x): return x // 0.2 """ Example 5: """ - +print('\n================\n') from linq.core.flow import extension_class, Flow @@ -104,3 +104,26 @@ def ToTupleGenerator(self: Flow): NameError: No extension method named `ToTupleGenerator` for builtins.object. """ print(seq.Take(10).Zip(seq.Take(10)).ToDict().ToTupleGenerator()) + + +""" +Example 6: +""" +print('\n================\n') + +seq2 = Flow(i for i in range(30)) +print(seq2.Depend(-1).Take(10).ToList().Unboxed()) + + +""" +Example 7: +""" +print('\n================\n') + +print(Flow(Deducer.determine(1, 2, 3, 4, 5)).ToList().Unboxed()) +# => [1, 2, 3, 4, 5] +print(Flow(0 + Deducer.determine(1, 2, 3, 4, 5)).ToList().Unboxed()) +# => [0, 1, 2, 3, 4, 5] +fib = Flow(Deducer.deduce(lambda x, y: x + y, 1, 1)) +print(fib.Take(10).ToList().Unboxed()) +# => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] From ec93655131d5ea31e6383c3be7f21cd5816c34dd Mon Sep 17 00:00:00 2001 From: Athedorer <1103713644@qq.com> Date: Wed, 27 Dec 2017 09:32:09 +0800 Subject: [PATCH 2/8] add some methods for some data structure --- linq/standard/list.py | 69 +++++++++++++++++++++++++++++++++++++++---- linq/standard/set.py | 9 ++++++ 2 files changed, 72 insertions(+), 6 deletions(-) diff --git a/linq/standard/list.py b/linq/standard/list.py index d3a1f7a..7e0dda4 100644 --- a/linq/standard/list.py +++ b/linq/standard/list.py @@ -22,19 +22,76 @@ def Extend(self: Flow, *others): @extension_class(list) -def Sort(self: Flow, by): - if not is_to_destruct(by): - by = destruct_func(by) - self.stream.sort(key=by) +def Appended(self: Flow, elem): + stream = self.stream[:] + [elem] + return Flow(stream) + + +@extension_class(list) +def Append(self: Flow, elem): + self.stream.append(elem) return self @extension_class(list) -def Reverse(self: Flow): - self.stream.reverse() +def Depended(self: Flow, elem): + stream = [elem] + self.stream[:] + return Flow(stream) + + +@extension_class(list) +def Depend(self: Flow, elem): + self.stream.insert(0, elem) return self @extension_class(list) def Reversed(self: Flow): return Flow(self.stream[::-1]) + + +@extension_class(list) +def Reverse(self: Flow): + self.stream.reverse() + return self + + +@extension_class(list) +def Removed(self: Flow, elem): + stream = self.stream[:].remove(elem) + return Flow(stream) + + +@extension_class(list) +def Remove(self: Flow, elem): + self.stream.remove(elem) + return self + + +@extension_class(list) +def Inserted(self: Flow, idx, elem): + stream = self.stream[:].insert(idx, elem) + return Flow(stream) + + +@extension_class(list) +def Insert(self: Flow, idx, elem): + self.stream.insert(idx, elem) + return self + + +@extension_class(list) +def Sorted(self: Flow, by): + if not is_to_destruct(by): + by = destruct_func(by) + stream = self.stream[:] + stream.sort(key=by) + return Flow(stream) + + +@extension_class(list) +def Sort(self: Flow, by): + if not is_to_destruct(by): + by = destruct_func(by) + self.stream.sort(key=by) + return self \ No newline at end of file diff --git a/linq/standard/set.py b/linq/standard/set.py index 64ee2e3..01dacd8 100644 --- a/linq/standard/set.py +++ b/linq/standard/set.py @@ -12,3 +12,12 @@ def Intersects(self: Flow, *others) -> {'others': 'Seq | Seq>'}: @extension_class(set) def Union(self: Flow, *others) -> {'others': 'Seq | Seq>'}: return Flow(set.union(self.stream, *[unbox_if_flow(other) for other in others])) + + +@extension_class(set) +def Difference(self: Flow, *others) -> {'others': 'Seq | Seq>'}: + return Flow(set.difference(self.stream, *[unbox_if_flow(other) for other in others])) + +@extension_class(set) +def Symmetric_difference(self: Flow, *other) -> {'others': 'Seq | Seq>'}: + return Flow(set.symmetric_difference(self.stream, *[unbox_if_flow(other) for other in others])) From 79c7f8a6c70d30826a80203d0ea5a6259bcceb44 Mon Sep 17 00:00:00 2001 From: Athedorer <1103713644@qq.com> Date: Fri, 29 Dec 2017 16:52:38 +0800 Subject: [PATCH 3/8] replace generators with deducer, add some method for list, set --- linq/core/collections.py | 58 +++++++++++++--------------------------- linq/standard/general.py | 6 ++--- linq/standard/list.py | 6 ++--- test_manual.py | 28 +++++++++++++++---- 4 files changed, 48 insertions(+), 50 deletions(-) diff --git a/linq/core/collections.py b/linq/core/collections.py index 3c3a96d..95f9fd9 100644 --- a/linq/core/collections.py +++ b/linq/core/collections.py @@ -1,43 +1,6 @@ from ..core.utils import concat_generator -class Generator: - def __init__(self, rule, start_elem): - self.rule = rule - self.start_elem = start_elem - - def __iter__(self): - now = self.start_elem - while True: - try: - yield now - now = self.rule(now) - except StopIteration: - break - - -class Unitter(Generator): - def __init__(self, unit): - def stop(_): - raise StopIteration() - - super().__init__(stop, unit) - - -class Scanner: - def __init__(self, rule, seq, start_elem): - self.rule = rule - self.seq = seq - self.start_elem = start_elem - - def __iter__(self): - last = self.start_elem - for now in self.seq: - acc = self.rule(last, now) - yield acc - last = acc - - class Deducer: def __init__(self, first, rest=None): self.first = first @@ -53,7 +16,16 @@ def determine(cls, *values): @classmethod def deduce(cls, f, *initializer): return cls(initializer[0], lambda: cls.deduce(f, *initializer[1:], - f(*initializer))) + f(*initializer))) + + @classmethod + def scan(cls, rule, seq, start_elem): + try: + last = start_elem + now = rule(last, next(seq)) + return cls(now, lambda: cls.scan(rule, seq, now)) + except StopIteration: + return cls(None, None) def __radd__(self, left): return Deducer(left, lambda: self.determine(self.first, *self.rest())) @@ -61,8 +33,16 @@ def __radd__(self, left): def __iter__(self): try: if self.first is None: - raise StopIteration() + raise StopIteration yield self.first yield from self.rest() except StopIteration: pass + + def __next__(self): + if self.first is None: + raise StopIteration + now = self.first + nex = 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 dbfd39c..1232892 100644 --- a/linq/standard/general.py +++ b/linq/standard/general.py @@ -1,4 +1,4 @@ -from ..core.collections import Scanner +from ..core.collections import Deducer from ..core.flow import * from ..core.utils import * from functools import reduce @@ -54,12 +54,12 @@ def Then(self: Flow, f): @extension_std def Scan(self: Flow, f, start_elem): - return Flow(Scanner(f, self.stream, start_elem)) + return Flow(Deducer.scan(f, self.stream, start_elem)) @extension_std def Reduce(self: Flow, f, start_elem=None): - return Flow(reduce(f, self.stream) if start_elem is None else reduce(f, self.stream)) + return Flow(reduce(f, self.stream) if start_elem is None else reduce(f, self.stream, start_elem)) @extension_std diff --git a/linq/standard/list.py b/linq/standard/list.py index 8af3f44..14cb3cf 100644 --- a/linq/standard/list.py +++ b/linq/standard/list.py @@ -23,7 +23,7 @@ def Extend(self: Flow, *others): @extension_class(list) def Appended(self: Flow, elem): - stream = self.stream[:] + [elem] + stream = self.stream + [elem] return Flow(stream) @@ -35,7 +35,7 @@ def Append(self: Flow, elem): @extension_class(list) def Depended(self: Flow, elem): - stream = [elem] + self.stream[:] + stream = [elem] + self.stream return Flow(stream) @@ -82,7 +82,7 @@ def Insert(self: Flow, idx, elem): @extension_class(list) def Sorted(self: Flow, by): - if not is_to_destruct(by): + if is_to_destruct(by): by = destruct_func(by) stream = self.stream[:] stream.sort(key=by) diff --git a/test_manual.py b/test_manual.py index 849b006..9383942 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: Flow): 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 From 04ff0743dedce6ae3373d53e3c713cd1a6f8b660 Mon Sep 17 00:00:00 2001 From: Athedorer <1103713644@qq.com> Date: Tue, 2 Jan 2018 15:36:05 +0800 Subject: [PATCH 4/8] delete unused import --- linq/core/collections.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/linq/core/collections.py b/linq/core/collections.py index 95f9fd9..dbdb0c6 100644 --- a/linq/core/collections.py +++ b/linq/core/collections.py @@ -1,6 +1,3 @@ -from ..core.utils import concat_generator - - class Deducer: def __init__(self, first, rest=None): self.first = first From 2f7c9e0a2c0f9780458a044393c8b4aeef2b0be7 Mon Sep 17 00:00:00 2001 From: Athedorer <1103713644@qq.com> Date: Tue, 2 Jan 2018 16:10:44 +0800 Subject: [PATCH 5/8] replace generator with deducer --- linq/standard/general.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/linq/standard/general.py b/linq/standard/general.py index 7fa8bd7..40fb265 100644 --- a/linq/standard/general.py +++ b/linq/standard/general.py @@ -48,13 +48,13 @@ def Then(self: object, f): @extension_std -def Scan(self: Flow, f, start_elem): - return Flow(Deducer.scan(f, self.stream, start_elem)) +def Scan(self: Iterable, f, start_elem): + return Deducer.scan(f, self, start_elem) @extension_std -def Reduce(self: Flow, f, start_elem=None): - return Flow(reduce(f, self.stream) if start_elem is None else reduce(f, self.stream, start_elem)) +def Reduce(self: Iterable, f, start_elem=None): + return reduce(f, self) if start_elem is None else reduce(f, self, start_elem) @extension_std From da6c5f4e75fd6ecb405226aac720de15ae3b0a7a Mon Sep 17 00:00:00 2001 From: Athedorer <1103713644@qq.com> Date: Tue, 2 Jan 2018 16:13:36 +0800 Subject: [PATCH 6/8] replace generator with deducer --- linq/core/collections.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/linq/core/collections.py b/linq/core/collections.py index dbdb0c6..e4b6d62 100644 --- a/linq/core/collections.py +++ b/linq/core/collections.py @@ -39,7 +39,6 @@ def __iter__(self): def __next__(self): if self.first is None: raise StopIteration - now = self.first - nex = self.rest() + now, nex = self.first, self.rest() self.first, self.rest = nex.first, nex.rest return now From f5b1ed8589f310d785d2b6e7f08ddbf756b51e55 Mon Sep 17 00:00:00 2001 From: Athedorer <1103713644@qq.com> Date: Tue, 23 Jan 2018 12:22:31 +0800 Subject: [PATCH 7/8] fixed scan bug --- linq/core/collections.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/linq/core/collections.py b/linq/core/collections.py index e4b6d62..4bdfa26 100644 --- a/linq/core/collections.py +++ b/linq/core/collections.py @@ -18,9 +18,10 @@ def deduce(cls, f, *initializer): @classmethod def scan(cls, rule, seq, start_elem): try: + iterator = iter(seq) last = start_elem - now = rule(last, next(seq)) - return cls(now, lambda: cls.scan(rule, seq, now)) + now = rule(last, next(iterator)) + return cls(now, lambda: cls.scan(rule, iterator, now)) except StopIteration: return cls(None, None) From d655e4da7f4d54f88f805e3c51ab4adb4633d4ee Mon Sep 17 00:00:00 2001 From: Athedorer <1103713644@qq.com> Date: Tue, 23 Jan 2018 13:05:01 +0800 Subject: [PATCH 8/8] compatible with py3.4 --- linq/core/collections.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/linq/core/collections.py b/linq/core/collections.py index 4bdfa26..03e84e1 100644 --- a/linq/core/collections.py +++ b/linq/core/collections.py @@ -12,8 +12,7 @@ def determine(cls, *values): @classmethod def deduce(cls, f, *initializer): - return cls(initializer[0], lambda: cls.deduce(f, *initializer[1:], - f(*initializer))) + return cls(initializer[0], lambda: cls.deduce(f, *(initializer[1:] + (f(*initializer),)))) @classmethod def scan(cls, rule, seq, start_elem):