Skip to main content

itertools with function chaining

Project description

https://github.com/cjrh/excitertools/workflows/Python%20application/badge.svg https://img.shields.io/badge/stdlib--only-yes-green.svg https://coveralls.io/repos/github/cjrh/excitertools/badge.svg?branch=master https://img.shields.io/pypi/pyversions/excitertools.svg https://img.shields.io/github/tag/cjrh/excitertools.svg https://img.shields.io/badge/install-pip%20install%20excitertools-ff69b4.svg https://img.shields.io/pypi/v/excitertools.svg https://img.shields.io/badge/calver-YYYY.MM.MINOR-22bfda.svg https://img.shields.io/badge/code%20style-black-000000.svg

excitertools

itertools in the form of function call chaining

API Documentation

range(*args) -> Iter[int]

Replacement for the builtin range function. This version returns an instance of excitertools.Iter to allow further iterable chaining.

All the same calling variations work because this function merely wraps the original function.

>>> range(3).collect()
[0, 1, 2]
>>> range(1, 4).collect()
[1, 2, 3]
>>> range(1, 6, 2).collect()
[1, 3, 5]
>>> range(1, 101, 3).filter(lambda x: x % 7 == 0).collect()
[7, 28, 49, 70, 91]

This example multiples, element by element, the series [0:5] with the series [1:6]. Two things to note: Firstly, Iter.zip is used to emit the tuples from each series. Secondly, Iter.starmap is used to receive those tuples into separate arguments in the lambda.

>>> range(5).zip(range(1, 6)).starmap(lambda x, y: x * y).collect()
[0, 2, 6, 12, 20]

When written in a single line as above, it can get difficult to follow the chain of logic if there are many processing steps. Parentheses in Python allow grouping such that expressions can be spread over multiple lines.

This is the same example as the prior one, but formatted to be spread over several lines. This is much clearer:

>>> # Written out differently
>>> (
...     range(5)
...         .zip(range(1, 6))
...         .starmap(lambda x, y: x * y)
...         .collect()
... )
[0, 2, 6, 12, 20]

If you wanted the sum instead, it isn’t necessary to do the collection at all:

>>> (
...     range(5)
...         .zip(range(1, 6))
...         .starmap(lambda x, y: x * y)
...         .sum()
... )
40

zip(*iterables: Any) -> Iter[Tuple[T, ...]]

Replacement for the builtin zip function. This version returns an instance of excitertools.Iter to allow further iterable chaining.

enumerate(iterable) -> Iter[Tuple[int, T]]

Replacement for the builtin enumerate function. This version returns an instance of excitertools.Iter to allow further iterable chaining.

map(func: Union[Callable[..., C], str], iterable) -> Iter[C]

>>> result = Iter('caleb').map(lambda x: (x, ord(x))).dict()
>>> assert result == {'a': 97, 'b': 98, 'c': 99, 'e': 101, 'l': 108}

>>> result = Iter('caleb').map('x, ord(x)').dict()
>>> assert result == {'a': 97, 'b': 98, 'c': 99, 'e': 101, 'l': 108}

filter(*args, iterable) -> Iter[T]

Replacement for the builtin filter function. This version returns an instance of excitertools.Iter to allow further iterable chaining.

count(*args) -> Iter[int]

Replacement for the itertools count function. This version returns an instance of excitertools.Iter to allow further iterable chaining.

cycle(iterable) -> Iter[T]

Replacement for the itertools count function. This version returns an instance of excitertools.Iter to allow further iterable chaining.

repeat(elem: C, times=None) -> Iter[C]

Replacement for the itertools count function. This version returns an instance of excitertools.Iter to allow further iterable chaining.

accumulate(func, iterable)

Replacement for the itertools accumulate function. This version returns an instance of excitertools.Iter to allow further iterable chaining.

chain(*iterables: Iterable[T]) -> Iter[T]

Replacement for the itertools chain function. This version returns an instance of excitertools.Iter to allow further iterable chaining.

chain_from_iterable(iterable) -> Iter[T]

Replacement for the itertools chain.from_iterable method. This version returns an instance of excitertools.Iter to allow further iterable chaining.

compress(selectors, iterable)

Replacement for the itertools compress function. This version returns an instance of excitertools.Iter to allow further iterable chaining.

dropwhile(pred, iterable)

Replacement for the itertools dropwhile function. This version returns an instance of excitertools.Iter to allow further iterable chaining.

filterfalse(pred, iterable)

Replacement for the itertools filterfalse function. This version returns an instance of excitertools.Iter to allow further iterable chaining.

groupby(iterable, key=None)

Replacement for the itertools groupby function. This version returns an instance of excitertools.Iter to allow further iterable chaining.

islice(*args, iterable) -> Iter

Replacement for the itertools islice function. This version returns an instance of excitertools.Iter to allow further iterable chaining.

starmap(func, iterable)

Replacement for the itertools starmap function. This version returns an instance of excitertools.Iter to allow further iterable chaining.

takewhile(pred, iterable)

Replacement for the itertools takewhile function. This version returns an instance of excitertools.Iter to allow further iterable chaining.

tee(iterable, n=2)

Replacement for the itertools tee function. This version returns an instance of excitertools.Iter to allow further iterable chaining.

zip_longest(*iterables, fillvalue=None)

Replacement for the itertools zip_longest function. This version returns an instance of excitertools.Iter to allow further iterable chaining. .. _Iter:

class Iter(Generic[T])

This is the docstring for the Iter class.

Each of the following methods of Iter describe how they work.

Test warning: ⚠

Iter.collect(self, container=list) -> List[T]

>>> Iter('abc').collect()
['a', 'b', 'c']
>>> Iter('abc').collect(str)
'abc'
>>> Iter('abcaaaabbbbccc').collect(set) == {'a', 'b', 'c'}
True

@classmethod Iter.open(cls, file, mode="r", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, ) -> Iter

Wrap the open() builtin precisely, but return an Iter instance to allow function chaining on the result.

>>> import tempfile
>>> with tempfile.TemporaryDirectory() as td:
...     open('text.txt', 'w').writelines(['abc\n', 'def\n', 'ghi\n'])
...     Iter.open('text.txt').filter(lambda line: 'def' in line).collect()
['def\n']

Note that this is a convenience method for reading from a file, not for writing. The function signature includes the mode parameter for parity with the builtin open() function, but only reading is supported.

@classmethod Iter.range(cls, *args) -> Iter[int]

Docstring TBD

Iter.zip(self, *iterables: Any) -> Iter[Tuple[T, ...]]

Docstring TBD

Iter.any(self) -> bool

Docstring TBD

Iter.all(self) -> bool

Docstring TBD

Iter.enumerate(self) -> Iter[Tuple[int, T]]

Docstring TBD

Iter.dict(self) -> Dict

Docstring TBD

Iter.map(self, func: Union[Callable[..., C], str]) -> Iter[C]

>>> result = Iter('caleb').map(lambda x: (x, ord(x))).dict()
>>> assert result == {'a': 97, 'b': 98, 'c': 99, 'e': 101, 'l': 108}
>>> result = Iter('caleb').map('x, ord(x)').dict()
>>> assert result == {'a': 97, 'b': 98, 'c': 99, 'e': 101, 'l': 108}

Iter.filter(self, *args) -> Iter[T]

Docstring TBD

Iter.reduce(self, func: Callable[..., T], *args) -> T

Docstring TBD

Iter.sum(self)

Docstring TBD

Iter.concat(self, glue: AnyStr) -> AnyStr

Docstring TBD

Iter.insert(self, glue: C) -> Iter[Union[C, T]]

Docstring TBD

@classmethod Iter.count(cls, *args) -> Iter[int]

Docstring TBD

Iter.cycle(self) -> Iter[T]

Docstring TBD

@classmethod Iter.repeat(cls, elem: C, times=None) -> Iter[C]

Docstring TBD

Iter.accumulate(self, func)

Docstring TBD

Iter.chain(self, *iterables: Iterable[T]) -> Iter[T]

Docstring TBD

Iter.chain_from_iterable(self) -> Iter[T]

Docstring TBD

Iter.compress(self, selectors)

Docstring TBD

Iter.dropwhile(self, pred)

Docstring TBD

Iter.filterfalse(self, pred)

Docstring TBD

Iter.groupby(self, key=None)

Docstring TBD

Iter.islice(self, *args) -> Iter

Docstring TBD

Iter.starmap(self, func)

Docstring TBD

Iter.takewhile(self, pred)

Docstring TBD

Iter.tee(self, n=2)

Docstring TBD

Iter.zip_longest(self, *iterables, fillvalue=None)

Docstring TBD

Iter.chunked(self, n: int) -> Iter

Docstring TBD

Iter.ichunked(self, n: int) -> Iter

Docstring TBD

@classmethod Iter.sliced(cls, seq: Sequence, n: int) -> Iter

Docstring TBD

Iter.distribute(self, n: int) -> Iter

Docstring TBD

Iter.divide(self, n: int) -> Iter

Docstring TBD

Iter.split_at(self, pred)

Docstring TBD

Iter.split_before(self, pred)

Docstring TBD

Iter.split_after(self, pred)

Docstring TBD

Iter.split_into(self, sizes)

Docstring TBD

Iter.split_when(self, pred)

Docstring TBD

Iter.bucket(self, key, validator=None)

Docstring TBD

Iter.unzip(self)

Docstring TBD

Iter.grouper(self, n: int, fillvalue=None) -> Iter

Docstring TBD

Iter.partition(self, pred) -> Iter

Docstring TBD

Iter.spy(self, n=1) -> Tuple[Iter, Iter]

Docstring TBD

Iter.peekable(self) -> more_itertools.peekable

Docstring TBD

Iter.seekable(self) -> more_itertools.seekable

Docstring TBD

Iter.windowed(self, n, fillvalue=None, step=1) -> Iter

Docstring TBD

Iter.substrings(self)

Docstring TBD

Iter.substrings_indexes(self, reverse=False)

Docstring TBD

Iter.stagger(self, offsets=(-1, 0, 1), longest=False, fillvalue=None)

>>> Iter([0, 1, 2, 3]).stagger().collect()
[(None, 0, 1), (0, 1, 2), (1, 2, 3)]
>>> Iter(range(8)).stagger(offsets=(0, 2, 4)).collect()
[(0, 2, 4), (1, 3, 5), (2, 4, 6), (3, 5, 7)]
>>> Iter([0, 1, 2, 3]).stagger(longest=True).collect()
[(None, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, None), (3, None, None)]

Iter.pairwise(self)

See https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.pairwise

>>> Iter.count().pairwise().take(4).collect()
[(0, 1), (1, 2), (2, 3), (3, 4)]

Iter.count_cycle(self, n=None) -> Iter

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.count_cycle

>>> Iter('AB').count_cycle(3).collect()
[(0, 'A'), (0, 'B'), (1, 'A'), (1, 'B'), (2, 'A'), (2, 'B')]

Iter.intersperse(self, e, n=1) -> Iter

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.intersperse

>>> Iter([1, 2, 3, 4, 5]).intersperse('!').collect()
[1, '!', 2, '!', 3, '!', 4, '!', 5]

>>> Iter([1, 2, 3, 4, 5]).intersperse(None, n=2).collect()
[1, 2, None, 3, 4, None, 5]

Iter.padded(self, fillvalue: Optional[C] = None, n: Optional[int] = None, next_multiple: bool = False, ) -> Iter[Union[T, C]]

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.padded

>>> Iter([1, 2, 3]).padded('?', 5).collect()
[1, 2, 3, '?', '?']

>>> Iter([1, 2, 3, 4]).padded(n=3, next_multiple=True).collect()
[1, 2, 3, 4, None, None]

Iter.repeat_last(self, default=None) -> Iter[T]

https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.repeat_last

>>> Iter(range(3)).repeat_last().islice(5).collect()
[0, 1, 2, 2, 2]

>>> Iter(range(0)).repeat_last(42).islice(5).collect()
[42, 42, 42, 42, 42]

Iter.adjacent(self, pred, distance=1) -> Iter[Tuple[bool, T]]

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.adjacent

>>> Iter(range(6)).adjacent(lambda x: x == 3).collect()
[(False, 0), (False, 1), (True, 2), (True, 3), (True, 4), (False, 5)]

>>> Iter(range(6)).adjacent(lambda x: x == 3, distance=2).collect()
[(False, 0), (True, 1), (True, 2), (True, 3), (True, 4), (True, 5)]

Iter.groupby_transform(self, keyfunc: Optional[Callable[..., K]] = None, valuefunc: Optional[Callable[..., V]] = None, ) -> Iter[Tuple[K, Iterable[V]]]

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.groupby_transform

This example has been modified somewhat from the original. We’re using starmap here to “unzip” the tuples produced by the group transform.

>>> iterable = 'AaaABbBCcA'
>>> keyfunc = lambda x: x.upper()
>>> valuefunc = lambda x: x.lower()
>>> (
...    Iter(iterable)
...        .groupby_transform(keyfunc, valuefunc)
...        .starmap(lambda k, g: (k, ''.join(g)))
...        .collect()
... )
[('A', 'aaaa'), ('B', 'bbb'), ('C', 'cc'), ('A', 'a')]

>>> from operator import itemgetter
>>> keys = [0, 0, 1, 1, 1, 2, 2, 2, 3]
>>> values = 'abcdefghi'
>>> iterable = zip(keys, values)
>>> (
...     Iter(iterable)
...        .groupby_transform(itemgetter(0), itemgetter(1))
...        .starmap(lambda k, g: (k, ''.join(g)))
...        .collect()
... )
[(0, 'ab'), (1, 'cde'), (2, 'fgh'), (3, 'i')]

Iter.padnone(self) -> Iter[Union[T, None]]

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.padnone

>>> Iter(range(3)).padnone().take(5).collect()
[0, 1, 2, None, None]

Iter.ncycles(self, n) -> Iter[T]

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.ncycles

>>> Iter(['a', 'b']).ncycles(3).collect()
['a', 'b', 'a', 'b', 'a', 'b']

Iter.collapse(self, base_type=None, levels=None) -> Iter

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.collapse

>>> iterable = [(1, 2), ([3, 4], [[5], [6]])]
>>> Iter(iterable).collapse().collect()
[1, 2, 3, 4, 5, 6]

>>> iterable = ['ab', ('cd', 'ef'), ['gh', 'ij']]
>>> Iter(iterable).collapse(base_type=tuple).collect()
['ab', ('cd', 'ef'), 'gh', 'ij']

>>> iterable = [('a', ['b']), ('c', ['d'])]
>>> Iter(iterable).collapse().collect() # Fully flattened
['a', 'b', 'c', 'd']
>>> Iter(iterable).collapse(levels=1).collect() # Only one level flattened
['a', ['b'], 'c', ['d']]

@class_or_instancemethod Iter.sort_together(self_or_cls, iterables, key_list=(0,), reverse=False)

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sort_together

This can be called either as an instance method or a class method. The classmethod form is more convenient if all the iterables are already available. The instancemethod form is more convenient if one of the iterables already goes through some transformation.

Here are examples from the classmethod form, which mirror the examples in the more-itertools documentation:

>>> iterables = [(4, 3, 2, 1), ('a', 'b', 'c', 'd')]
>>> Iter.sort_together(iterables).collect()
[(1, 2, 3, 4), ('d', 'c', 'b', 'a')]

>>> iterables = [(3, 1, 2), (0, 1, 0), ('c', 'b', 'a')]
>>> Iter.sort_together(iterables, key_list=(1, 2)).collect()
[(2, 3, 1), (0, 0, 1), ('a', 'c', 'b')]

>>> Iter.sort_together([(1, 2, 3), ('c', 'b', 'a')], reverse=True).collect()
[(3, 2, 1), ('a', 'b', 'c')]

Here is an examples using the instancemethod form:

>>> iterables = [('a', 'b', 'c', 'd')]
>>> Iter([4, 3, 2, 1]).sort_together(iterables).collect()
[(1, 2, 3, 4), ('d', 'c', 'b', 'a')]

@class_or_instancemethod Iter.interleave(self_or_cls, *iterables) -> Iter

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.interleave

Classmethod form:

>>> Iter.interleave([1, 2, 3], [4, 5], [6, 7, 8]).collect()
[1, 4, 6, 2, 5, 7]

Instancemethod form:

>>> Iter([1, 2, 3]).interleave([4, 5], [6, 7, 8]).collect()
[1, 4, 6, 2, 5, 7]

@class_or_instancemethod Iter.interleave_longest(self_or_cls, *iterables) -> Iter

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.interleave_longest

Classmethod form:

>>> Iter.interleave_longest([1, 2, 3], [4, 5], [6, 7, 8]).collect()
[1, 4, 6, 2, 5, 7, 3, 8]

Instancemethod form:

>>> Iter([1, 2, 3]).interleave_longest([4, 5], [6, 7, 8]).collect()
[1, 4, 6, 2, 5, 7, 3, 8]

@classmethod Iter.zip_offset(cls, *iterables, offsets, longest=False, fillvalue=None) -> Iter

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.zip_offset

>>> Iter.zip_offset('0123', 'abcdef', offsets=(0, 1)).collect()
[('0', 'b'), ('1', 'c'), ('2', 'd'), ('3', 'e')]

>>> Iter.zip_offset('0123', 'abcdef', offsets=(0, 1), longest=True).collect()
[('0', 'b'), ('1', 'c'), ('2', 'd'), ('3', 'e'), (None, 'f')]

Iter.dotproduct(self, vec2: Iterable)

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.dotproduct

>>> Iter([10, 10]).dotproduct([20, 20])
400

Iter.flatten(self) -> Iter[T]

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.flatten

>>> Iter([[0, 1], [2, 3]]).flatten().collect()
[0, 1, 2, 3]

@class_or_instancemethod Iter.roundrobin(self_or_cls: Union[Type[T], T], *iterables: C) -> Iter[Union[T, C]]

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.roundrobin

Classmethod form:

>>> Iter.roundrobin('ABC', 'D', 'EF').collect()
['A', 'D', 'E', 'B', 'F', 'C']

Instancemethod form:

>>> Iter('ABC').roundrobin('D', 'EF').collect()
['A', 'D', 'E', 'B', 'F', 'C']

Iter.prepend(self, value: C) -> Iter[Union[T, C]]

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.prepend

>>> value = '0'
>>> iterator = ['1', '2', '3']
>>> Iter(iterator).prepend(value).collect()
['0', '1', '2', '3']

Iter.ilen(self) -> int

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.ilen

>>> Iter(x for x in range(1000000) if x % 3 == 0).ilen()
333334

Iter.unique_to_each(self) -> Iter[T]

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.unique_to_each

>>> Iter([{'A', 'B'}, {'B', 'C'}, {'B', 'D'}]).unique_to_each().collect()
[['A'], ['C'], ['D']]

>>> Iter(["mississippi", "missouri"]).unique_to_each().collect()
[['p', 'p'], ['o', 'u', 'r']]

Iter.sample(self, k=1, weights=None) -> Iter

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sample

>>> iterable = range(100)
>>> Iter(iterable).sample(5).collect()  # doctest: +SKIP
[81, 60, 96, 16, 4]

>>> iterable = range(100)
>>> weights = (i * i + 1 for i in range(100))
>>> Iter(iterable).sample(5, weights=weights)  # doctest: +SKIP
[79, 67, 74, 66, 78]

>>> data = "abcdefgh"
>>> weights = range(1, len(data) + 1)
>>> Iter(data).sample(k=len(data), weights=weights)  # doctest: +SKIP
['c', 'a', 'b', 'e', 'g', 'd', 'h', 'f']


>>> # This one just to let the doctest run
>>> iterable = range(100)
>>> Iter(iterable).sample(5).map(lambda x: 0 <= x < 100).all()
True

Iter.consecutive_groups(self, ordering=lambda x: x)

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.consecutive_groups

>>> iterable = [1, 10, 11, 12, 20, 30, 31, 32, 33, 40]
>>> Iter(iterable).consecutive_groups().map(lambda g: list(g)).print('{v}').consume()
[1]
[10, 11, 12]
[20]
[30, 31, 32, 33]
[40]

Iter.run_length_encode(self) -> Iter[Tuple[T, int]]

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.run_length

>>> uncompressed = 'abbcccdddd'
>>> Iter(uncompressed).run_length_encode().collect()
[('a', 1), ('b', 2), ('c', 3), ('d', 4)]

Iter.run_length_decode(self) -> Iter

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.run_length

>>> compressed = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
>>> Iter(compressed).run_length_decode().collect()
['a', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd', 'd']

Iter.map_reduce(self, keyfunc, valuefunc=None, reducefunc=None) -> Dict

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.map_reduce

This interface mirrors what more-itertools does in that it returns a dict. See map_reduce_it() for a slightly-modified interface that returns the dict items as another iterator.

>>> keyfunc = lambda x: x.upper()
>>> d = Iter('abbccc').map_reduce(keyfunc)
>>> sorted(d.items())
[('A', ['a']), ('B', ['b', 'b']), ('C', ['c', 'c', 'c'])]

>>> keyfunc = lambda x: x.upper()
>>> valuefunc = lambda x: 1
>>> d = Iter('abbccc').map_reduce(keyfunc, valuefunc)
>>> sorted(d.items())
[('A', [1]), ('B', [1, 1]), ('C', [1, 1, 1])]

>>> keyfunc = lambda x: x.upper()
>>> valuefunc = lambda x: 1
>>> reducefunc = sum
>>> d = Iter('abbccc').map_reduce(keyfunc, valuefunc, reducefunc)
>>> sorted(d.items())
[('A', 1), ('B', 2), ('C', 3)]

Note the warning given in the more-itertools docs about how lists are created before the reduce step. This means you always want to filter before applying map_reduce, not after.

>>> all_items = _range(30)
>>> keyfunc = lambda x: x % 2  # Evens map to 0; odds to 1
>>> categories = Iter(all_items).filter(lambda x: 10<=x<=20).map_reduce(keyfunc=keyfunc)
>>> sorted(categories.items())
[(0, [10, 12, 14, 16, 18, 20]), (1, [11, 13, 15, 17, 19])]
>>> summaries = Iter(all_items).filter(lambda x: 10<=x<=20).map_reduce(keyfunc=keyfunc, reducefunc=sum)
>>> sorted(summaries.items())
[(0, 90), (1, 75)]

Iter.map_reduce_it(self, keyfunc: Callable[..., K], valuefunc: Optional[Callable[..., V]] = None, reducefunc: Optional[Callable[..., R]] = None) -> Iter[Tuple[K, R]]

See: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.map_reduce

>>> keyfunc = lambda x: x.upper()
>>> Iter('abbccc').map_reduce_it(keyfunc).collect()
[('A', ['a']), ('B', ['b', 'b']), ('C', ['c', 'c', 'c'])]

>>> keyfunc = lambda x: x.upper()
>>> valuefunc = lambda x: 1
>>> Iter('abbccc').map_reduce_it(keyfunc, valuefunc).collect()
[('A', [1]), ('B', [1, 1]), ('C', [1, 1, 1])]

>>> keyfunc = lambda x: x.upper()
>>> valuefunc = lambda x: 1
>>> reducefunc = sum
>>> Iter('abbccc').map_reduce_it(keyfunc, valuefunc, reducefunc).collect()
[('A', 1), ('B', 2), ('C', 3)]

Iter.exactly_n(self, n, predicate=bool) -> Iter

Iter.all_equal(self)

Iter.first_true(self)

Iter.quantify(self)

Iter.islice_extended(self, *args)

Iter.first(self)

Iter.last(self)

Iter.one(self)

Iter.only(self, default=None, too_long=None) -> Any

Iter.strip(self, pred)

Iter.lstrip(self, pred)

Iter.rstrip(self, pred)

Iter.filter_except(self, validator, *exceptions)

Iter.map_except(self, function, *exceptions)

Iter.nth_or_last(self)

Iter.nth(self, n, default=None)

Iter.take(self, n: int) -> Iter

Iter.tail(self)

Iter.unique_everseen(self)

Iter.unique_justseen(self)

Iter.distinct_permutations(self)

Iter.distinct_combinations(self, r)

Iter.circular_shifts(self) -> Iter

Iter.partitions(self) -> Iter

Iter.set_partitions(self, k=None) -> Iter

Iter.powerset(self)

Iter.random_product(self)

Iter.random_permutation(self)

Iter.random_combination(self)

Iter.random_combination_with_replacement(self)

Iter.nth_combination(self)

Iter.always_iterable(self)

Iter.always_reversible(self)

Iter.consumer(self)

Iter.with_iter(self)

Iter.iter_except(self)

Iter.locate(self, pred=bool, window_size=None) -> Iter

Iter.rlocate(self, pred=bool, window_size=None) -> Iter

Iter.replace(self, pred, substitutes, count=None, window_size=1) -> Iter

@classmethod Iter.numeric_range(cls, *args) -> Iter

Iter.side_effect(self, func, chunk_size=None, before=None, after=None)

Iter.iterate(self)

Iter.difference(self, func=operator.sub, *, initial=None)

Iter.make_decorator(self)

Iter.SequenceView(self)

Iter.time_limited(self, limit_seconds) -> Iter

Iter.consume(self, n: Optional[int] = None) -> Optional[Iter[T]]

If n is not provided, the entire iterator is consumed and None is returned. Otherwise, an iterator will always be returned, even if n is greater than the number of items left in the iterator.

Iter.tabulate(self)

Iter.repeatfunc(self)

Iter.wrap(self, ends: Sequence[T, T] = "()")

Other examples for ends: ‘”’ * 2, or ‘`’ * 2, or ‘[]’ etc.

Iter.print(self, template="{i}: {v}") -> Iter[T]

Printing during the execution of an iterator. Mostly useful for debugging. Returns another iterator instance through which the original data is passed unchanged. This means you can include a print() step as necessary to observe data during iteration.

>>> Iter('abc').print().collect()
0: a
1: b
2: c
['a', 'b', 'c']

>>> (
...    Iter(range(5))
...        .print('before filter {i}: {v}')
...        .filter(lambda x: x > 2)
...        .print('after filter {i}: {v}')
...        .collect()
... )
before filter 0: 0
before filter 1: 1
before filter 2: 2
before filter 3: 3
after filter 0: 3
before filter 4: 4
after filter 1: 4
[3, 4]

🛠 class IterDict(UserDict)

The idea here was to make a custom dict where several of the standard dict methods return Iter instances, which can then be chained. I’m not sure if this will be kept yet.

IterDict.keys(self) -> Iter

IterDict.values(self) -> Iter

IterDict.items(self) -> Iter

IterDict.update(self, *args, **kwargs) -> IterDict

insert_separator(iterable: Iterable[Any], glue: Any) -> Iterable[Any]

Similar functionality can be obtained with, e.g., interleave, as in

>>> result = Iter('caleb').interleave(Iter.repeat('x')).collect()
>>> result == list('cxaxlxexbx')
True

But you’ll see a trailing “x” there, which join avoids. join makes sure to only add the glue separator if another element has arrived.

It can handle strings without any special considerations, but it doesn’t do any special handling for bytes and bytearrays. For that, rather look at concat().

concat(iterable: Iterable[AnyStr], glue: AnyStr) -> AnyStr

Concatenate strings, bytes and bytearrays. It is careful to avoid the problem with single bytes becoming integers, and it looks at the value of glue to know whether to handle bytes or strings.

This function can raise ValueError if called with something other than bytes, bytearray or str.

Dev Instructions

For general dev:

$ python -m venv venv
$ source venv/bin/activate
(venv) $ pip install -e .[dev,test]

To run the tests:

(venv) $ pytest

To regenerate the file README.rst:

(venv) $ python regenerate_readme.py -m excitertools.py > README.rst

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

excitertools-0.0.3.tar.gz (29.0 kB view hashes)

Uploaded Source

Built Distribution

excitertools-0.0.3-py3-none-any.whl (13.6 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page