diff --git a/lib/assets/Lib/itertools.py b/lib/assets/Lib/itertools.py new file mode 100644 --- /dev/null +++ b/lib/assets/Lib/itertools.py @@ -0,0 +1,505 @@ +import operator + +class accumulate: + def __init__(self, iterable, func = operator.add): + self.it = iter(iterable) + self._total = None + self.func = func + + def __iter__(self): + return self + + def __next__(self): + if not self._total: + self._total = next(self.it) + return self._total + else: + element = next(self.it) + try: + self._total = self.func(self._total, element) + except: + raise TypeError("unsupported operand type") + return self._total + +## Adapted from: +## https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-34 +class chain: + def __init__(self, *iterables): + self._iterables_iter = iter(map(iter, iterables)) + # little trick for the first chain.__next__() call + self._cur_iterable_iter = iter([]) + + def __iter__(self): + return self + + def __next__(self): + while True: + try: + return next(self._cur_iterable_iter) + except StopIteration: + self._cur_iterable_iter = next(self._iterables_iter) + + @classmethod + def from_iterable(cls, iterable): + for it in iterable: + for element in it: + yield element + +class combinations: + def __init__(self, iterable, r): + self.pool = tuple(iterable) + self.n = len(self.pool) + self.r = r + self.indices = list(range(self.r)) + self.zero = False + + def __iter__(self): + return self + + def __next__(self): + if self.r > self.n: + raise StopIteration + if not self.zero: + self.zero = True + return tuple(self.pool[i] for i in self.indices) + else: + try: + for i in reversed(range(self.r)): + if self.indices[i] != i + self.n - self.r: + break + self.indices[i] += 1 + for j in range(i+1, self.r): + self.indices[j] = self.indices[j-1] + 1 + return tuple(self.pool[i] for i in self.indices) + except: + raise StopIteration + +class combinations_with_replacement: + def __init__(self, iterable, r): + self.pool = tuple(iterable) + self.n = len(self.pool) + self.r = r + self.indices = [0] * self.r + self.zero = False + + def __iter__(self): + return self + + def __next__(self): + if not self.n and self.r: + raise StopIteration + if not self.zero: + self.zero = True + return tuple(self.pool[i] for i in self.indices) + else: + try: + for i in reversed(range(self.r)): + if self.indices[i] != self.n - 1: + break + self.indices[i:] = [self.indices[i] + 1] * (self.r - i) + return tuple(self.pool[i] for i in self.indices) + except: + raise StopIteration + +## Literally copied from +##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-63 +class compress: + def __init__(self, data, selectors): + self.data = iter(data) + self.selectors = iter(selectors) + + def __iter__(self): + return self + + def __next__(self): + while True: + next_item = next(self.data) + next_selector = next(self.selectors) + if bool(next_selector): + return next_item + +## Adapted from +##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-79 +## I mimicked the > python3.1 behavior +class count: + """ + Input is an int or a float. The original Python 3 implementation + includes also complex numbers... but it still is not implemented + in Brython as complex type is NotImplemented + """ + def __init__(self, start = 0, step = 1): + if not isinstance(start, (int, float)): + raise TypeError('a number is required') + self.times = start - step + self.step = step + + def __iter__(self): + return self + + def __next__(self): + self.times += self.step + return self.times + + def __repr__(self): + return 'count(%d)' % (self.times + self.step) + +## Literally copied from +##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-112 +class cycle: + def __init__(self, iterable): + self._cur_iter = iter(iterable) + self._saved = [] + self._must_save = True + + def __iter__(self): + return self + + def __next__(self): + try: + next_elt = next(self._cur_iter) + if self._must_save: + self._saved.append(next_elt) + except StopIteration: + self._cur_iter = iter(self._saved) + next_elt = next(self._cur_iter) + self._must_save = False + return next_elt + +## Literally copied from +##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-149 +class dropwhile: + def __init__(self, predicate, iterable): + self._predicate = predicate + self._iter = iter(iterable) + self._dropped = False + + def __iter__(self): + return self + + def __next__(self): + value = next(self._iter) + if self._dropped: + return value + while self._predicate(value): + value = next(self._iter) + self._dropped = True + return value + +## Adapted from +##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-261 +class filterfalse: + def __init__(self, predicate, iterable): + # Make sure iterable *IS* iterable + self._iter = iter(iterable) + if predicate is None: + self._predicate = bool + else: + self._predicate = predicate + + def __iter__(self): + return self + def __next__(self): + next_elt = next(self._iter) + while True: + if not self._predicate(next_elt): + return next_elt + next_elt = next(self._iter) + +class groupby: + # [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B + # [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D + def __init__(self, iterable, key=None): + if key is None: + key = lambda x: x + self.keyfunc = key + self.it = iter(iterable) + self.tgtkey = self.currkey = self.currvalue = object() + def __iter__(self): + return self + def __next__(self): + while self.currkey == self.tgtkey: + self.currvalue = next(self.it) # Exit on StopIteration + self.currkey = self.keyfunc(self.currvalue) + self.tgtkey = self.currkey + return (self.currkey, self._grouper(self.tgtkey)) + def _grouper(self, tgtkey): + while self.currkey == tgtkey: + yield self.currvalue + self.currvalue = next(self.it) # Exit on StopIteration + self.currkey = self.keyfunc(self.currvalue) + +## adapted from +##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-323 +class islice: + def __init__(self, iterable, *args): + s = slice(*args) + self.start, self.stop, self.step = s.start or 0, s.stop, s.step + if not isinstance(self.start, int): + raise ValueError("Start argument must be an integer") + if self.stop != None and not isinstance(self.stop, int): + raise ValueError("Stop argument must be an integer or None") + if self.step is None: + self.step = 1 + if self.start<0 or (self.stop != None and self.stop<0 + ) or self.step<=0: + raise ValueError("indices for islice() must be positive") + self.it = iter(iterable) + self.donext = None + self.cnt = 0 + + def __iter__(self): + return self + + def __next__(self): + nextindex = self.start + if self.stop != None and nextindex >= self.stop: + raise StopIteration + while self.cnt <= nextindex: + nextitem = next(self.it) + self.cnt += 1 + self.start += self.step + return nextitem + +class permutations: + def __init__(self, iterable, r = None): + self.pool = tuple(iterable) + self.n = len(self.pool) + self.r = self.n if r is None else r + self.indices = list(range(self.n)) + self.cycles = list(range(self.n, self.n - self.r, -1)) + self.zero = False + self.stop = False + + def __iter__(self): + return self + + def __next__(self): + indices = self.indices + if self.r > self.n: + raise StopIteration + if not self.zero: + self.zero = True + return tuple(self.pool[i] for i in indices[:self.r]) + + i = self.r - 1 + while i >= 0: + j = self.cycles[i] - 1 + if j > 0: + self.cycles[i] = j + indices[i], indices[-j] = indices[-j], indices[i] + return tuple(self.pool[i] for i in indices[:self.r]) + self.cycles[i] = len(indices) - i + n1 = len(indices) - 1 + assert n1 >= 0 + num = indices[i] + for k in range(i, n1): + indices[k] = indices[k+1] + indices[n1] = num + i -= 1 + raise StopIteration + +# copied from Python documentation on itertools.product +def product(*args, repeat=1): + # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy + # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111 + pools = [tuple(pool) for pool in args] * repeat + result = [[]] + for pool in pools: + result = [x+[y] for x in result for y in pool] + for prod in result: + yield tuple(prod) + + +## adapted from +##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-392 + +## (Brython) +## renamed to _product : the implementation fails for product('abc', []) +## with CPython 3.x +class _product: + def __init__(self, *args, **kw): + if len(kw) > 1: + raise TypeError("product() takes at most 1 argument (%d given)" % + len(kw)) + self.repeat = kw.get('repeat', 1) + if not isinstance(self.repeat, int): + raise TypeError("integer argument expected, got %s" % + type(self.repeat)) + self.gears = [x for x in args] * self.repeat + self.num_gears = len(self.gears) + # initialization of indicies to loop over + self.indicies = [(0, len(self.gears[x])) + for x in range(0, self.num_gears)] + self.cont = True + self.zero = False + + def roll_gears(self): + # Starting from the end of the gear indicies work to the front + # incrementing the gear until the limit is reached. When the limit + # is reached carry operation to the next gear + should_carry = True + for n in range(0, self.num_gears): + nth_gear = self.num_gears - n - 1 + if should_carry: + count, lim = self.indicies[nth_gear] + count += 1 + if count == lim and nth_gear == 0: + self.cont = False + if count == lim: + should_carry = True + count = 0 + else: + should_carry = False + self.indicies[nth_gear] = (count, lim) + else: + break + + def __iter__(self): + return self + + def __next__(self): + if self.zero: + raise StopIteration + if self.repeat > 0: + if not self.cont: + raise StopIteration + l = [] + for x in range(0, self.num_gears): + index, limit = self.indicies[x] + print('itertools 353',self.gears,x,index) + l.append(self.gears[x][index]) + self.roll_gears() + return tuple(l) + elif self.repeat == 0: + self.zero = True + return () + else: + raise ValueError("repeat argument cannot be negative") + +## Literally copied from +##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-441 +class repeat: + def __init__(self, obj, times=None): + self._obj = obj + if times is not None: + range(times) # Raise a TypeError + if times < 0: + times = 0 + self._times = times + + def __iter__(self): + return self + + def __next__(self): + # __next__() *need* to decrement self._times when consumed + if self._times is not None: + if self._times <= 0: + raise StopIteration() + self._times -= 1 + return self._obj + + def __repr__(self): + if self._times is not None: + return 'repeat(%r, %r)' % (self._obj, self._times) + else: + return 'repeat(%r)' % (self._obj,) + + def __len__(self): + if self._times == -1 or self._times is None: + raise TypeError("len() of uniszed object") + return self._times + +## Adapted from +##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-489 +class starmap(object): + def __init__(self, function, iterable): + self._func = function + self._iter = iter(iterable) + + def __iter__(self): + return self + + def __next__(self): + t = next(self._iter) + return self._func(*t) + +## Literally copied from +##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-520 +class takewhile(object): + def __init__(self, predicate, iterable): + self._predicate = predicate + self._iter = iter(iterable) + + def __iter__(self): + return self + + def __next__(self): + value = next(self._iter) + if not self._predicate(value): + raise StopIteration() + return value + +## Almost literal from +##https://bitbucket.org/pypy/pypy/src/c1aa74c06e86/lib_pypy/itertools.py#cl-547 +class TeeData(object): + def __init__(self, iterator): + self.data = [] + self._iter = iterator + + def __getitem__(self, i): + # iterates until 'i' if not done yet + while i>= len(self.data): + self.data.append(next(self._iter)) + return self.data[i] + + +class TeeObject(object): + def __init__(self, iterable=None, tee_data=None): + if tee_data: + self.tee_data = tee_data + self.pos = 0 + # <=> Copy constructor + elif isinstance(iterable, TeeObject): + self.tee_data = iterable.tee_data + self.pos = iterable.pos + else: + self.tee_data = TeeData(iter(iterable)) + self.pos = 0 + + def __next__(self): + data = self.tee_data[self.pos] + self.pos += 1 + return data + + def __iter__(self): + return self + + +def tee(iterable, n=2): + if isinstance(iterable, TeeObject): + return tuple([iterable] + + [TeeObject(tee_data=iterable.tee_data) for i in range(n - 1)]) + tee_data = TeeData(iter(iterable)) + return tuple([TeeObject(tee_data=tee_data) for i in range(n)]) + +class zip_longest: + def __init__(self, *args, fillvalue = None): + self.args = [iter(arg) for arg in args] + self.fillvalue = fillvalue + self.units = len(args) + + def __iter__(self): + return self + + def __next__(self): + temp = [] + nb = 0 + for i in range(self.units): + try: + temp.append(next(self.args[i])) + nb += 1 + except StopIteration: + temp.append(self.fillvalue) + if nb==0: + raise StopIteration + return tuple(temp)