# Module sequtils

Author: | Alex Mitchell

This module implements operations for the built-in seq type which were inspired by functional programming languages. If you are looking for the typical map function which applies a function to every element in a sequence, it already exists in the system module in both mutable and immutable styles.

Also, for functional style programming you may want to pass anonymous procs to procs like `filter` to reduce typing. Anonymous procs can use the special do notation which is more convenient in certain situations.

Note: This interface will change as soon as the compiler supports closures and proper coroutines.

# Imports

strutils

# Procs

    proc concat[T](seqs: varargs[seq[T]]): seq[T]

  Takes several sequences' items and returns them inside a new sequence.

  Example:

      let
        s1 = @[1, 2, 3]
        s2 = @[4, 5]
        s3 = @[6, 7]
        total = concat(s1, s2, s3)
      assert total == @[1, 2, 3, 4, 5, 6, 7]

    proc distnct[T](seq1: seq[T]): seq[T]

  Returns a new sequence without duplicates.

  This proc is misspelled on purpose to avoid a clash with the keyword `distinct` used to define a derived type incompatible with its base type. Example:

      let
        dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
        dup2 = @["a", "a", "c", "d", "d"]
        unique1 = distnct(dup1)
        unique2 = distnct(dup2)
      assert unique1 == @[1, 3, 4, 2, 8]
      assert unique2 == @["a", "c", "d"]

    proc zip[S, T](seq1: seq[S]; seq2: seq[T]): seq[tuple[a: S, b: T]]

  Returns a new sequence with a combination of the two input sequences.

  For convenience you can access the returned tuples through the named fields a and b. If one sequence is shorter, the remaining items in the longer sequence are discarded. Example:

      let
        short = @[1, 2, 3]
        long = @[6, 5, 4, 3, 2, 1]
        words = @["one", "two", "three"]
        zip1 = zip(short, long)
        zip2 = zip(short, words)
      assert zip1 == @[(1, 6), (2, 5), (3, 4)]
      assert zip2 == @[(1, "one"), (2, "two"), (3, "three")]
      assert zip1[2].b == 4
      assert zip2[2].b == "three"

    proc filter[T](seq1: seq[T]; pred: proc (item: T): bool {.closure.}): seq[T]

  Returns a new sequence with all the items that fulfilled the predicate.

  Example:

      let
        colors = @["red", "yellow", "black"]
        f1 = filter(colors, proc(x: string): bool = x.len < 6)
        f2 = filter(colors) do (x: string) -> bool : x.len > 5
      assert f1 == @["red", "black"]
      assert f2 == @["yellow"]

# Iterators

    iterator filter[T](seq1: seq[T]; pred: proc (item: T): bool {.closure.}): T

  Iterates through a sequence and yields every item that fulfills the predicate.

  Example:

      let numbers = @[1, 4, 5, 8, 9, 7, 4]
      for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
        echo($n)
      # echoes 4, 8, 4 in separate lines

# Templates

    template filterIt(seq1, pred: expr): expr {.immediate.}

  Returns a new sequence with all the items that fulfilled the predicate.

  Unlike the proc version, the predicate needs to be an expression using the `it` variable for testing, like: `filterIt("abcxyz", it == 'x')`. Example:

      let
        temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44]
        acceptable = filterIt(temperatures, it < 50 and it > -10)
        notAcceptable = filterIt(temperatures, it > 50 or it < -10)
      assert acceptable == @[-2.0, 24.5, 44.31]
      assert notAcceptable == @[-272.15, 99.9, -113.44]

    template toSeq(iter: expr): expr {.immediate.}

  Transforms any iterator into a sequence.

  Example:

      let
        numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
        odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
          if x mod 2 == 1:
            result = true)
      assert odd_numbers == @[1, 3, 5, 7, 9]

    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:

      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"

    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:

      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"

Generated: 2013-05-21 09:55:22 UTC