diff options
Diffstat (limited to 'lib/pure/collections')
-rw-r--r-- | lib/pure/collections/sequtils.nim | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 502acc61b..451a1dc7f 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -151,6 +151,78 @@ template toSeq*(iter: expr): expr {.immediate.} = for x in iter: add(result, x) result +template foldl*(sequence, operation: expr): expr = + ## Template to fold a sequence from left to right, returning the accumulation. + ## + ## The sequence is required to have at least a single element. Debug versions + ## of your program will assert in this situation but release versions will + ## happily go ahead. If the sequence has a single element it will be returned + ## without applying ``operation``. + ## + ## The ``operation`` parameter should be an expression which uses the + ## variables ``a`` and ``b`` for each step of the fold. Since this is a left + ## fold, for non associative binary operations like substraction think that + ## the sequence of numbers 1, 2 and 3 will be parenthesized as (((1) - 2) - + ## 3). Example: + ## + ## .. code-block:: nimrod + ## let + ## numbers = @[5, 9, 11] + ## addition = foldl(numbers, a + b) + ## substraction = foldl(numbers, a - b) + ## multiplication = foldl(numbers, a * b) + ## words = @["nim", "rod", "is", "cool"] + ## concatenation = foldl(words, a & b) + ## assert addition == 25, "Addition is (((5)+9)+11)" + ## assert substraction == -15, "Substraction is (((5)-9)-11)" + ## assert multiplication == 495, "Multiplication is (((5)*9)*11)" + ## assert concatenation == "nimrodiscool" + assert sequence.len > 0, "Can't fold empty sequences" + var result {.gensym.}: type(sequence[0]) + result = sequence[0] + for i in countup(1, sequence.len - 1): + let + a {.inject.} = result + b {.inject.} = sequence[i] + result = operation + result + +template foldr*(sequence, operation: expr): expr = + ## Template to fold a sequence from right to left, returning the accumulation. + ## + ## The sequence is required to have at least a single element. Debug versions + ## of your program will assert in this situation but release versions will + ## happily go ahead. If the sequence has a single element it will be returned + ## without applying ``operation``. + ## + ## The ``operation`` parameter should be an expression which uses the + ## variables ``a`` and ``b`` for each step of the fold. Since this is a right + ## fold, for non associative binary operations like substraction think that + ## the sequence of numbers 1, 2 and 3 will be parenthesized as (1 - (2 - + ## (3))). Example: + ## + ## .. code-block:: nimrod + ## let + ## numbers = @[5, 9, 11] + ## addition = foldr(numbers, a + b) + ## substraction = foldr(numbers, a - b) + ## multiplication = foldr(numbers, a * b) + ## words = @["nim", "rod", "is", "cool"] + ## concatenation = foldr(words, a & b) + ## assert addition == 25, "Addition is (5+(9+(11)))" + ## assert substraction == 7, "Substraction is (5-(9-(11)))" + ## assert multiplication == 495, "Multiplication is (5*(9*(11)))" + ## assert concatenation == "nimrodiscool" + assert sequence.len > 0, "Can't fold empty sequences" + var result {.gensym.}: type(sequence[0]) + result = sequence[sequence.len - 1] + for i in countdown(sequence.len - 2, 0): + let + a {.inject.} = sequence[i] + b {.inject.} = result + result = operation + result + when isMainModule: import strutils block: # concat test @@ -210,4 +282,30 @@ when isMainModule: result = true) assert odd_numbers == @[1, 3, 5, 7, 9] + block: # foldl tests + let + numbers = @[5, 9, 11] + addition = foldl(numbers, a + b) + substraction = foldl(numbers, a - b) + multiplication = foldl(numbers, a * b) + words = @["nim", "rod", "is", "cool"] + concatenation = foldl(words, a & b) + assert addition == 25, "Addition is (((5)+9)+11)" + assert substraction == -15, "Substraction is (((5)-9)-11)" + assert multiplication == 495, "Multiplication is (((5)*9)*11)" + assert concatenation == "nimrodiscool" + + block: # foldr tests + let + numbers = @[5, 9, 11] + addition = foldr(numbers, a + b) + substraction = foldr(numbers, a - b) + multiplication = foldr(numbers, a * b) + words = @["nim", "rod", "is", "cool"] + concatenation = foldr(words, a & b) + assert addition == 25, "Addition is (5+(9+(11)))" + assert substraction == 7, "Substraction is (5-(9-(11)))" + assert multiplication == 495, "Multiplication is (5*(9*(11)))" + assert concatenation == "nimrodiscool" + echo "Finished doc tests" |