Skip to content

Instantly share code, notes, and snippets.

@Varriount
Created February 6, 2014 23:30
Show Gist options
  • Save Varriount/8854701 to your computer and use it in GitHub Desktop.
Save Varriount/8854701 to your computer and use it in GitHub Desktop.
## 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