Commits

Lynn Rees committed 988ac50

- prune merge
- eliminate coroutines

Comments (0)

Files changed (6)

twoq/filtering.py

 
     '''collecting mixin'''
 
-    @classmethod
-    def _extract(cls, truth, subcall, transform, iterable):
-        '''
-        collect members of things
-
-        @param call: "Truth" filter
-        @param truth: second "Truth" filter
-        @param iterable: an iterable
-        '''
-        def members():
-            f, s, t, i = truth, subcall, transform, iterable
-            d, w, g, e = dir, cls._extract, getattr, AttributeError
-            test = lambda x: x.startswith('__') or x.startswith('mro')
-            for k in filterfalse(test, d(i)):
-                try:
-                    v = g(i, k)
-                except e:
-                    pass
-                else:
-                    if s(v):
-                        yield k, t(w(f, s, t, v))
-                    else:
-                        yield k, v
-        for member in ifilter(truth, members()):
-            yield member
-
-    @staticmethod
-    def _pick(names, iterable):
-        '''
-        collect attributes of things in iterable
-
-        @param names: sequence of names
-        @param iterable: an iterable
-        '''
-        attrfind = attrgetter(*names)
-        for thing in iterable:
-            try:
-                yield attrfind(thing)
-            except AttributeError:
-                pass
-
-    @staticmethod
-    def _pluck(keys, iterable, _itemgetter=itemgetter):
-        '''
-        collect values of things in iterable
-
-        @param keys: sequence of keys
-        @param iterable: an iterable
-        '''
-        itemfind = _itemgetter(*keys)
-        IndexError_, KeyError_, TypeError_ = IndexError, KeyError, TypeError
-        for thing in iterable:
-            try:
-                yield itemfind(thing)
-            except (IndexError_, KeyError_, TypeError_):
-                pass
-
     def members(self):
         '''extract object members from incoming things'''
+        def extract(truth, subcall, transform, iterable):
+            def members():
+                f, s, t, i = truth, subcall, transform, iterable
+                d, w, g, e = dir, extract, getattr, AttributeError
+                test = lambda x: x.startswith('__') or x.startswith('mro')
+                for k in filterfalse(test, d(i)):
+                    try:
+                        v = g(i, k)
+                    except e:
+                        pass
+                    else:
+                        if s(v):
+                            yield k, t(w(f, s, t, v))
+                        else:
+                            yield k, v
+            for member in ifilter(truth, members()):
+                yield member
         with self._context():
-            walk_ = self._extract
+            walk_ = extract
             call_, alt_, wrap_ = self._call, self._alt, self._wrapper
             return self._xtend(ichain(imap(
                 lambda x: walk_(call_, alt_, wrap_, x), self._iterable,
 
     def pick(self, *names):
         '''collect object attributes from incoming things by their `*names`'''
+        def pick(names, iterable):
+            '''
+            collect attributes of things in iterable
+    
+            @param names: sequence of names
+            @param iterable: an iterable
+            '''
+            attrfind = attrgetter(*names)
+            for thing in iterable:
+                try:
+                    yield attrfind(thing)
+                except AttributeError:
+                    pass
         with self._context():
-            return self._xtend(self._pick(names, self._iterable))
+            return self._xtend(pick(names, self._iterable))
 
     def pluck(self, *keys):
         '''collect object items from incoming things by item `*keys`'''
+        def pluck(keys, iterable, _itemgetter=itemgetter):
+            '''
+            collect values of things in iterable
+    
+            @param keys: sequence of keys
+            @param iterable: an iterable
+            '''
+            itemfind = _itemgetter(*keys)
+            IndexErr_, KeyErr_, TypeErr_ = IndexError, KeyError, TypeError
+            for thing in iterable:
+                try:
+                    yield itemfind(thing)
+                except (IndexErr_, KeyErr_, TypeErr_):
+                    pass
         with self._context():
-            return self._xtend(self._pluck(keys, self._iterable))
+            return self._xtend(pluck(keys, self._iterable))
 
 
 class SetMixin(local):
 
     '''set and uniqueness mixin'''
 
-    @classmethod
-    def _unique(cls, iterable, key=None):
-        '''
-        unique things in in iterable
-
-        @param iterable: an iterable
-        @param key: determine uniqueness filter
-        '''
-        seen = set()
-        seen_add_ = seen.add
-        key_ = key
-        for element in iterable:
-            k = key_(element)
-            if k not in seen:
-                seen_add_(k)
-                yield element
-
     def difference(self):
         '''difference between incoming things'''
         with self._context():
         list unique incoming things, preserving order and remember all incoming
         things ever seen
         '''
+        def unique(iterable, key=None):
+            seen = set()
+            seen_add_, key_ = seen.add, key
+            for element in iterable:
+                k = key_(element)
+                if k not in seen:
+                    seen_add_(k)
+                    yield element
         with self._context():
-            return self._iter(self._unique(self._iterable, self._call))
+            return self._iter(unique(self._iterable, self._call))
 
 
 class SliceMixin(local):
 
     '''delayed map mixin'''
 
-    @staticmethod
-    def _delay_each(x, y, wait=0, caller=None):
-        '''
-        invoke `caller` with passed arguments, keywords after a delay
-
-        @param x: positional arguments
-        @param y: keywork arguments
-        @param wait: time in seconds to delay (default: 0)
-        @param caller: a callable (default: None)
-        '''
-        sleep(wait)
-        return caller(*x, **y)
-
-    @staticmethod
-    def _delay_invoke(x, wait=0, caller=None):
-        '''
-        invoke method on object after a delay but return object instead of call
-        result if the call returns None
-
-        @param x: some thing
-        @param wait: time in seconds to delay (default: 0)
-        @param caller: a callable (default: None)
-        '''
-        sleep(wait)
-        results = caller(x)
-        return x if results is None else results
-
-    @staticmethod
-    def _delay_map(x, wait=None, caller=None):
-        '''
-        invoke call on thing after a delay
-
-        @param wait: time in seconds to delay (default: 0)
-        @param caller: a callable (default: None)
-        '''
-        sleep(wait)
-        return caller(x)
-
     def delay_each(self, wait):
         '''
         invoke call with passed arguments, keywords in incoming things after
 
         @param wait: time in seconds
         '''
+        def delay_each(x, y, wait=0, caller=None):
+            sleep(wait)
+            return caller(*x, **y)
         with self._context():
-            de, call = self._delay_each, self._call
+            de, call = delay_each, self._call
             return self._xtend(starmap(
                 lambda x, y: de(x, y, wait, call), self._iterable,
             ))
         @param name: name of method
         @param wait: time in seconds
         '''
+        def delay_invoke(x, wait=0, caller=None):
+            sleep(wait)
+            results = caller(x)
+            return x if results is None else results
         with self._context():
-            di, mc = self._delay_invoke, methodcaller
+            di, mc = delay_invoke, methodcaller
             args, kw = self._args, self._kw
             return self._xtend(imap(
                 lambda x: di(x, wait, mc(name, *args, **kw)), self._iterable,
 
         @param wait: time in seconds
         '''
+        def delay_map(x, wait=None, caller=None):
+            sleep(wait)
+            return caller(x)
         with self._context():
-            dm, call = self._delay_map, self._call
+            dm, call = delay_map, self._call
             return self._xtend(imap(
                 lambda x: dm(x, wait, call), self._iterable,
             ))
 
     '''mapping mixin'''
 
-    @staticmethod
-    def _invoke(thing, caller=None):
-        '''
-        invoke method on object but return object instead of call result if the
-        call returns None
-
-        @param thing: some thing
-        @param caller: a callable (default: None)
-        '''
-        results = caller(thing)
-        return thing if results is None else results
-
-    def map(self):
-        '''invoke call on each incoming thing'''
+    def each(self):
+        '''invoke call with passed arguments, keywords in incoming things'''
         with self._context():
-            return self._xtend(imap(self._call, self._iterable))
+            return self._xtend(starmap(
+                lambda x, y: self._call(*x, **y), self._iterable,
+            ))
 
     def invoke(self, name):
         '''
 
         @param name: name of method
         '''
+        def invoke(thing, caller=None):
+            results = caller(thing)
+            return thing if results is None else results
         with self._context():
-            invoke = self._invoke
             return self._xtend(imap(
                 lambda x: invoke(
                     x, caller=methodcaller(name, *self._args, **self._kw)
                 self._iterable
             ))
 
-    def each(self):
-        '''invoke call with passed arguments, keywords in incoming things'''
-        with self._context():
-            return self._xtend(starmap(
-                lambda x, y: self._call(*x, **y), self._iterable,
-            ))
-
-    def starmap(self):
-        '''invoke call on each sequence of incoming things'''
-        with self._context():
-            return self._xtend(starmap(self._call, self._iterable))
-
     def items(self):
         '''invoke call on each mapping to get key, value pairs'''
         with self._context():
                 self._call, ichain(imap(items, self._iterable))
             ))
 
+    def map(self):
+        '''invoke call on each incoming thing'''
+        with self._context():
+            return self._xtend(imap(self._call, self._iterable))
+
+    def starmap(self):
+        '''invoke call on each sequence of incoming things'''
+        with self._context():
+            return self._xtend(starmap(self._call, self._iterable))
+
 
 class MappingMixin(DelayMixin, RepeatMixin, MapMixin):
 
                 zip_longest(fillvalue=fill, *[iter(self._iterable)] * n)
             )
 
+    def product(self, n=1):
+        '''
+        nested for each loops repeated `n` times
+
+        @param n: number of repetitions (default: 1)
+        '''
+        with self._context():
+            return self._xtend(product(*self._iterable, repeat=n))
+
     def reverse(self):
         '''reverse order of incoming things'''
         with self._context():
         with self._context():
             return self._xtend(sorted(self._iterable, key=call_))
 
-    def product(self, n=1):
-        '''
-        nested for each loops repeated `n` times
-
-        @param n: number of repetitions (default: 1)
-        '''
-        with self._context():
-            return self._xtend(product(*self._iterable, repeat=n))
-
 
 class OrderingMixin(OrderMixin, RandomMixin):
 
 '''twoq reducing mixins'''
 
 from math import fsum
-from heapq import merge
 from threading import local
 from collections import Iterable
 from functools import partial, reduce
 
     '''math mixin'''
 
-    @classmethod
-    def _average(cls, iterable):
-        '''average of `iterable`'''
-        i1, i2 = tee(iterable)
-        return truediv(sum(i1, 0.0), len(list(i2)))
-
-    @classmethod
-    def _median(cls, iterable):
-        '''median of `iterable`'''
-        i = list(sorted(iterable))
-        e = truediv(len(i) - 1, 2)
-        p = int(e)
-        return i[p] if e % 2 == 0 else truediv(i[p] + i[p + 1], 2)
-
     def average(self):
         '''average of all incoming things'''
+        def average(iterable):
+            '''average of `iterable`'''
+            i1, i2 = tee(iterable)
+            return truediv(sum(i1, 0.0), len(list(i2)))
         with self._context():
-            return self._append(self._average(self._iterable))
+            return self._append(average(self._iterable))
 
     def fsum(self):
         '''add incoming things together'''
 
     def median(self):
         '''median of all incoming things'''
+        def median(iterable):
+            '''median of `iterable`'''
+            i = list(sorted(iterable))
+            e = truediv(len(i) - 1, 2)
+            p = int(e)
+            return i[p] if e % 2 == 0 else truediv(i[p] + i[p + 1], 2)
         with self._context():
-            return self._append(self._median(self._iterable))
+            return self._append(median(self._iterable))
 
     def min(self):
         '''find minimum thing in incoming things using call as key function'''
 
     '''reduce mixin'''
 
-    @classmethod
-    def _roundrobin(cls, iterable):
-        '''
-        interleave things in iterable into one thing
-
-        @param iterable: an iterable
-        '''
-        islice_, next_, cycle_ = islice, next, cycle
-        nexts_ = cycle_(partial(next_, iter(i)) for i in iterable)
-        pending = len(tee(iterable, 1))
-        while pending:
-            try:
-                for nextz in nexts_:
-                    yield nextz()
-            except StopIteration:
-                pending -= 1
-                nexts_ = cycle_(islice_(nexts_, pending))
-
-    @classmethod
-    def _smash(cls, iterable):
-        '''
-        flatten deeply nested iterable
-
-        @param iterable: an iterable
-        '''
-        isstring_, Iterable_, smash_ = isstring, Iterable, cls._smash
-        for i in iterable:
-            if isinstance(i, Iterable_) and not isstring_(i):
-                for j in smash_(i):
-                    yield j
-            else:
-                yield i
-
-    def merge(self):
-        '''flatten nested but ordered incoming things'''
+    def flatten(self):
+        '''flatten deeply nested incoming things'''
+        def smash(iterable):
+            isstring_, Iterable_, smash_ = isstring, Iterable, smash
+            for i in iterable:
+                if isinstance(i, Iterable_) and not isstring_(i):
+                    for j in smash_(i):
+                        yield j
+                else:
+                    yield i
         with self._context():
-            return self._xtend(merge(*self._iterable))
+            return self._xtend(smash(self._iterable))
 
     def pairwise(self):
         '''every two incoming things as a tuple'''
 
     def roundrobin(self):
         '''interleave incoming things into one thing'''
+        def roundrobin(iterable):
+            islice_, next_, cycle_ = islice, next, cycle
+            nexts_ = cycle_(partial(next_, iter(i)) for i in iterable)
+            pending = len(tee(iterable, 1))
+            while pending:
+                try:
+                    for nextz in nexts_:
+                        yield nextz()
+                except StopIteration:
+                    pending -= 1
+                    nexts_ = cycle_(islice_(nexts_, pending))
         with self._context():
-            return self._xtend(self._roundrobin(self._iterable))
-
-    def flatten(self):
-        '''flatten deeply nested incoming things'''
-        with self._context():
-            return self._xtend(self._smash(self._iterable))
+            return self._xtend(roundrobin(self._iterable))
 
     def zip(self):
         '''

twoq/tests/auto/reducing.py

             self.qclass([[1, [2], [3, [[4]]]]]).flatten().end(), [1, 2, 3, 4],
         )
 
-    def test_merge(self):
-        self.assertEqual(
-            self.qclass([4, 5, 6], [1, 2, 3]).merge().end(),
-            [1, 2, 3, 4, 5, 6],
-        )
-
     def test_pairwise(self):
         self.assertEqual(
             self.qclass(

twoq/tests/man/reducing.py

             [1, 2, 3, 4],
         )
 
-    def test_merge(self):
-        self._false_true_false(
-            self.qclass([4, 5, 6], [1, 2, 3]).merge(),
-            self.assertEqual,
-            [1, 2, 3, 4, 5, 6],
-        )
-
     def test_pairwise(self):
         self._false_true_false(
             self.qclass(