#!usr/bin/env python3
import itertools


# itertools is a module that's not technically a set of built-in functions but
# it is part of the standard library that comes with python.
# it's useful for for creating and using iterators.
def main():
    print('some infinite iterators')
    # cycle iterator can be used to cycle over a collection over and over
    seq1 = ["Joe", "John", "Mike"]
    cycle1 = itertools.cycle(seq1)
    print(next(cycle1))
    print(next(cycle1))
    print(next(cycle1))
    print(next(cycle1))
    print(next(cycle1))

    # use count to create a simple counter
    count1 = itertools.count(100, 3)
    print(next(count1))
    print(next(count1))
    print(next(count1))

    print('some non-infinite iterators')
    values = [10, 5, 20, 30, 40, 50, 40, 30]

    # accumulate creates an iterator that accumulates/aggregates values
    print(list(itertools.accumulate(values)))  # this defaults to addition
    print(list(itertools.accumulate(values, max)))
    print(list(itertools.accumulate(values, min)))

    # use chain to connect sequences together
    x = itertools.chain('ABCD', '1234')
    print(list(x))

    # dropwhile and takewhile will return values until
    # a certain condition is met that stops them. they are similar to the
    # filter built-in function.
    # dropwhile will drop the values from the sequence as long as the
    # condition of the function is true and then returns the rest of values
    print(list(itertools.dropwhile(is_less_than_forty, values)))
    # takewhile will keep the values from the sequence as long as the
    # condition of the function is true and then stops giving data
    print(list(itertools.takewhile(is_less_than_forty, values)))


def is_less_than_forty(x):
    return x < 40


if __name__ == "__main__":
    main()

# CONSOLE OUTPUT:
# some infinite iterators
# Joe
# John
# Mike
# Joe
# John
# 100
# 103
# 106
# some non-infinite iterators
# [10, 15, 35, 65, 105, 155, 195, 225]
# [10, 10, 20, 30, 40, 50, 50, 50]
# [10, 5, 5, 5, 5, 5, 5, 5]
# ['A', 'B', 'C', 'D', '1', '2', '3', '4']
# [40, 50, 40, 30]
# [10, 5, 20, 30]

[((12, 13, 12, 34), 'itertools.cycle', 'itertools.cycle', ({(12, 29, 12, 33): 'seq1'}, {}), '(seq1)', False, 'import itertools\n'), ((20, 13, 20, 36), 'itertools.count', 'itertools.count', ({(20, 29, 20, 32): '100', (20, 34, 20, 35): '3'}, {}), '(100, 3)', False, 'import itertools\n'), ((34, 8, 34, 39), 'itertools.chain', 'itertools.chain', ({(34, 24, 34, 30): '"""ABCD"""', (34, 32, 34, 38): '"""1234"""'}, {}), "('ABCD', '1234')", False, 'import itertools\n'), ((29, 15, 29, 43), 'itertools.accumulate', 'itertools.accumulate', ({(29, 36, 29, 42): 'values'}, {}), '(values)', False, 'import itertools\n'), ((30, 15, 30, 48), 'itertools.accumulate', 'itertools.accumulate', ({(30, 36, 30, 42): 'values', (30, 44, 30, 47): 'max'}, {}), '(values, max)', False, 'import itertools\n'), ((31, 15, 31, 48), 'itertools.accumulate', 'itertools.accumulate', ({(31, 36, 31, 42): 'values', (31, 44, 31, 47): 'min'}, {}), '(values, min)', False, 'import itertools\n'), ((42, 15, 42, 62), 'itertools.dropwhile', 'itertools.dropwhile', ({(42, 35, 42, 53): 'is_less_than_forty', (42, 55, 42, 61): 'values'}, {}), '(is_less_than_forty, values)', False, 'import itertools\n'), ((45, 15, 45, 62), 'itertools.takewhile', 'itertools.takewhile', ({(45, 35, 45, 53): 'is_less_than_forty', (45, 55, 45, 61): 'values'}, {}), '(is_less_than_forty, values)', False, 'import itertools\n')]