Created
February 6, 2014 23:30
-
-
Save Varriount/8854701 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## Nimrod Itertools, based on the python itertools module | |
## Written by Clay Sweetser | |
## | |
## Please note that, like the nimrod countX iterators, anything | |
## dealing with ranges is inclusive. | |
## Also note that, while efforts have been made to make these iterators | |
## Resistant to errors regarding parameters which change from iteration | |
## to iteration, nothing can be guaranteed. | |
discard """ | |
Unfinished iterators: | |
accumulate | |
compress - Done, Needs Test | |
dropwhile - Done, Needs Test | |
filter - Done, Needs Test | |
filterfalse - Done, Needs Test | |
groupby | |
islice | |
starmap | |
takewhile | |
tee | |
zip_longest | |
product | |
permutations | |
combinations | |
combinations_with_replacement | |
take | |
tabulate | |
consume | |
nth | |
quantify | |
padnone | |
ncycles | |
dotproduct | |
flatten | |
repeatfunc | |
pairwise | |
grouper | |
roundrobin | |
partition | |
powerset | |
unique_everseen | |
unique_justseen | |
random_product | |
random_permutation | |
random_combination | |
random_combination_with_replacement | |
""" | |
import typeinfo | |
import macros | |
# Utilities | |
type | |
ordT = typedesc | |
intT = typedesc | |
iterator countX(oT=typedesc, start, stop: oT, step: int): oT = | |
var value = start | |
if step > 0 and start <= stop: | |
while value <= stop: | |
yield value | |
inc(value, step) | |
elif step < 0 and start >= stop: | |
while value >= stop: | |
yield value | |
dec(value, step) | |
else: | |
assert False | |
# Infinite Iterators | |
iterator count* [ordT](start: ordT, step = 1): ordT {.closure.} = | |
## An iterator function that returns evenly spaced values of ordinal T, | |
## starting with `start` | |
## Note, this doesn't have any protections against overflow errors! | |
## | |
## Parameters: | |
## start: A starting ordinal | |
## step: The space between returned values. | |
var i = start | |
if step < 0: | |
while True: | |
dec(i, step) | |
yield i | |
if step > 0: | |
while True: | |
inc(i, step) | |
yield i | |
when defined(isMainModule): | |
block countBlock: | |
let | |
countRange = 1..5 | |
endSeq = @[5,10,15,20,25] | |
var | |
startSeq = newSeq[int]() | |
countIterator = count[int] | |
for i in 1..5: | |
startSeq.add(countIterator(0,5)) | |
assert(startSeq == endSeq) | |
echo(repr(startSeq)) | |
iterator cycle* [iterT, returnT](iter:iterT): returnT = | |
## An iterator returning elements from the iterable and saving a | |
## copy of each. When the iterable is exhausted, return elements | |
## from the saved copy. Repeats indefinitely. | |
## | |
## Parameters: | |
## iter: The iterator to cycle through | |
var cont: seq[returnT] | |
newSeq(cont, 0) | |
for element in iter: | |
yield element | |
cont.add(element) | |
while True: | |
for element in cont: | |
yield element | |
when false and defined(isMainModule): | |
block cycleBlock: | |
var cycleSeq = @[1,2] | |
var emptySeq = newSeq[int]() | |
var cycleIterator = cycle[seq[int], int] | |
for i in 1..3: | |
emptySeq.add(cycleIterator(cycleSeq)) | |
assert(emptySeq == @[1,2,1,2,1,2]) | |
echo(repr(emptySeq)) | |
iterator repeat* [elemT](elem: elemT, count = 0): elemT {.closure.} = | |
## An iterator which repeats the given element endlessly, or up to | |
## X times, inclusive. | |
## | |
## Parameters: | |
## elem: The element to repeat | |
## count: The number of times to repeat. Zero or less repeats infinitely. | |
if count <= 0: | |
while True: | |
yield elem | |
else: | |
var c = 0 | |
while c <= count: | |
inc(c, 1) | |
yield elem | |
when defined(isMainModule): | |
block repeatBlock: | |
let | |
repeatRange = 1..5 | |
endSeq = @[5,5,5,5,5] | |
var | |
startSeq = newSeq[int]() | |
repeatIterator = count[int] | |
for i in 1..5: | |
startSeq.add(repeatIterator(5, 0)) | |
echo(repr(startSeq)) | |
assert(startSeq == endSeq) | |
# Iterators terminating on the shortest input sequence | |
iterator chain* [iterT, resT](iterlist: varargs[iterT]): resT {.closure.} = | |
## Make an iterator that returns elements from the first iterable | |
## until it is exhausted, then proceeds to the next iterable, until | |
## all of the iterables are exhausted. Used for treating consecutive | |
## sequences as a single sequence. | |
## | |
## Arguments: | |
## iterList: A sequence of iterables. | |
for iter in iterlist: | |
for element in iter: | |
yield element | |
when defined(isMainModule): | |
block chainBlock: | |
let | |
endSeq = @[5,4,5,6,5] | |
var | |
startSeq = @[@[5,4],@[5,6],@[5]] | |
chainIterator = chain[int] | |
for i in 1..5: | |
startSeq.add(chainIterator(5, 0)) | |
echo(repr(startSeq)) | |
assert(startSeq == endSeq) | |
iterator compress* [dT, sT, rT](data: dT, selectors: sT): rT {.closure.} = | |
## Make an iterator that filters elements from data returning only | |
## those that have a corresponding element in selectors that evaluates | |
## to True. Stops when either the data or selectors iterables has | |
## been exhausted. | |
## TODO - Specify length determination method | |
var minLength = min(data.len, selectors.len) | |
for i in 0..minLength-1: | |
if selectors[i] == True: | |
yield data[i] | |
else: | |
continue | |
type filterProc[T] = proc (value:T): bool | |
iterator dropWhile* [iT, rT](predicate: filterProc[rT], iter: iT): rT {.closure.} = | |
var unbroken = false | |
for element in iter: | |
if unbroken and not predicate(element): | |
unbroken = false | |
yield element | |
yield element | |
#iterator groupBy | |
iterator iFilter* [iT, rT](predicate: filterProc[rT], iter: iT): rT {.closure.} = | |
for element in iter: | |
if predicate(element) == true: | |
yield element | |
else: | |
continue | |
iterator iFilterFalse* [iT, rT](predicate: filterProc[rT], iter: iT): rT {.closure.} = | |
for element in iter: | |
if not predicate(element): | |
yield element | |
else: | |
continue | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment