Search results

There are no results.

std.csv.Parser

class pub Parser[I: mut + Read]

A type for parsing a CSV stream.

A Parser can parse any type that implements std.io.Read, and offers two ways of parsing the data:

  • A low-level API optimized for low memory usage and control over the parsing process
  • A high-level iterator API that prioritises ease of use of control and memory usage

The Parser type is capable of handling both \r\n and \n as the line endings. Lines that end with just \r are considered invalid and result in the parser producing an Error.

The default separator used is a comma, this can be changed using the method Parser.separator=.

Low-level parsing

The low-level API gives full control over the parsing process and makes it possible to parse large CSV streams while keeping memory usage as low as possible.

Parsing using the low-level API is done using the following methods:

  • Parser.column? to check if there's data to parse as a column
  • Parser.column to parse column data as a String
  • Parser.next_line to advance the stream to the next line

A typical parsing loop (ignoring proper error handling for the sake of clarity) using this API looks as follows:

import std.csv (Parser)
import std.io (Buffer)

let parser = Parser.new(Buffer.new('foo,bar,baz\r\n1,2,3'))
let rows = []

loop {
  let row = []

  # Parse each column, until we reach the end of the line.
  while parser.column?.get { row.push(parser.column.get) }

  # This ensures empty rows don't result in an empty `[]`, which isn't useful.
  if row.size > 0 { rows.push(row) }

  # Advance to the next line, and break the loop if there's no more data to
  # parse.
  if parser.next_line.get.false? { break }
}

If the number of columns and their positions is known, you can also write the following:

import std.csv (Parser)
import std.io (Buffer)

let parser = Parser.new(Buffer.new('foo,bar,baz\r\n1,2,3'))
let rows = []

loop {
  # This ensures that if the row is entirely empty we just skip it, instead
  # of producing an error.
  if parser.column?.get {
    rows.push([parser.column.get, parser.column.get, parser.column.get])
  }

  if parser.next_line.get.false? { break }
}

You can also skip columns and entire lines using Parser.skip_column and Parser.skip_line respectively, and skip multiple columns in a single call using Parser.skip_columns.

High-level parsing

For cases where the CSV data is small, or you just want to parse something quickly and don't care about the amount of memory used, the low-level API can be a bit verbose. To make dealing with such cases easier, the Parser type implements std.iter.Iter. For example, to iterate over the results of parsing each line:

import std.csv (Parser)
import std.io (Buffer)

let parser = Parser.new(Buffer.new('foo,bar,baz\r\n1,2,3'))

parser.each(fn (result) {
  # ...
})

Because parsing a line may produce an error, Parser yields values of type Option[Result[Array[String], Error]] rather than Option[Array[String]]. This means you need to handle errors when processing the result values. A simple way of doing so is to use std.iter.Iter.try_reduce:

import std.csv (Parser)
import std.io (Buffer)

let parser = Parser.new(Buffer.new('foo,bar,baz\r\n1,2,3'))
let rows = parser
  .try_reduce([], fn (rows, result) {
    rows.push(try result)
    Result.Ok(rows)
  })
  .get

rows # => [['foo', 'bar', 'baz'], ['1', '2', '3']]

Static methods

new

Show source code
Hide source code
fn pub static new(input: I) -> Parser[I] {
  Parser(
    input: BufferedReader.new(input),
    buffer: ByteArray.new,
    offset: 0,
    separator: Separator.Comma.to_int,
  )
}
fn pub static new(input: I: mut) -> Parser[I: mut]

Returns a new Parser that uses a comma as the column separator.

Examples

import std.csv (Parser)
import std.io (Buffer)

Parser.new(Buffer.new('foo,bar,baz'))

Instance methods

all?

Show source code
Hide source code
fn pub mut all?(func: fn (T) -> Bool) -> Bool {
  loop {
    match self.next {
      case Some(v) -> if func.call(v).false? { return false }
      case _ -> return true
    }
  }
}
fn pub mut all?(func: fn (T) -> Bool) -> Bool

Returns true if the supplied func returns true for all values in self.

This method stops iterating over the values after the first value for which the closure returns false.

Examples

Checking if all values in an Iter match a condition:

[10, 20].iter.all? fn (value) { value.positive? } # => true
[-1, 20].iter.all? fn (value) { value.positive? } # => false

any?

Show source code
Hide source code
fn pub mut any?(func: fn (T) -> Bool) -> Bool {
  loop {
    match self.next {
      case Some(v) -> if func.call(v) { return true }
      case _ -> return false
    }
  }
}
fn pub mut any?(func: fn (T) -> Bool) -> Bool

Returns true if self contains any value for which the func argument returned true.

This method stops iterating over the values after the first matching value.

Examples

Checking if an Iter contains a value:

[10, 20, 30].iter.any? fn (value) { value >= 20 } # => true

chain

Show source code
Hide source code
fn pub move chain[I: mut + Iter[T]](other: I) -> Stream[T] {
  let mut iter_left = true

  Stream.new(fn move {
    if iter_left {
      let item = self.next

      if item.some? { return item } else { iter_left = false }
    }

    other.next
  })
}
fn pub move chain[I: mut + Iter[T]](other: I: mut) -> Stream[T]

Join two Iter objects together, one after another.

Examples

let a = [10, 20, 30]
let b = [40, 50, 60]
a.iter.chain(b.iter).to_array == [10, 20, 30, 40, 50, 60] # => true

chunks

Show source code
Hide source code
fn pub move chunks(size: Int) -> Stream[Array[T]] {
  Stream.new(fn move {
    let chunk = []

    while chunk.size < size {
      match self.next {
        case Some(val) -> chunk.push(val)
        case _ -> break
      }
    }

    if chunk.empty? { Option.None } else { Option.Some(chunk) }
  })
}
fn pub move chunks(size: Int) -> Stream[Array[T]]

Returns an Iter that produces chunks of values.

Each chunk is up to the amount specified by the size argument. If the number of values can't be evenly divided, the last chunk may contain fewer than size elements.

column

Show source code
Hide source code
fn pub mut column -> Result[String, Error] {
  try read_column
  Result.Ok(@buffer.drain_to_string)
}
fn pub mut column -> Result[String, Error]

Parses a single column, returning its value as a String.

Errors

This method returns an Error for cases such as:

  • Reading data from the underlying stream fails
  • No more columns remain
  • The column format is invalid

Examples

import std.csv (Parser)
import std.io (Buffer)

let parser = Parser.new(Buffer.new('foo'))

parser.column # => Result.Ok('foo')

column?

Show source code
Hide source code
fn pub mut column? -> Result[Bool, Error] {
  match try peek {
    case Some(CR or LF) or None -> Result.Ok(false)
    case Some(_) -> Result.Ok(true)
  }
}
fn pub mut column? -> Result[Bool, Error]

Returns a boolean indicating if there's data left to parse as a column.

Errors

This method may need to read from the underlying stream to determine if data is available. If this fails, an Error is returned.

Examples

import std.csv (Parser)
import std.io (Buffer)

let parser = Parser.new(Buffer.new('foo'))

parser.column? # => true

count

Show source code
Hide source code
fn pub move count -> Int {
  reduce(0, fn (count, _) { count + 1 })
}
fn pub move count -> Int

Returns the number of values remaining in this iterator.

This method advances the iterator to the end.

Examples

[1, 2, 3].iter.count # => 3

each

Show source code
Hide source code
fn pub move each(func: fn (T)) {
  loop {
    match self.next {
      case Some(v) -> func.call(v)
      case _ -> return
    }
  }
}
fn pub move each(func: fn (T))

Calls the closure for every value in self.

Examples

let vals = [10, 20, 30]
let iter = vals.iter

iter.each fn (num) {
  num # => 10, 20, 30
}

each_with_index

Show source code
Hide source code
fn pub move each_with_index(func: fn (Int, T)) {
  let mut idx = 0

  each(fn move (value) { func.call(idx := idx + 1, value) })
}
fn pub move each_with_index(func: fn (Int, T))

Calls the closure for every value in self, passing an index and the value to the closure.

Examples

let vals = [10, 20, 30]
let iter = vals.iter

iter.each_with_index fn (index, num) {
  index # => 0, 1, 2
  num   # => 10, 20, 30
}

find

Show source code
Hide source code
fn pub mut find(func: fn (ref T) -> Bool) -> Option[T] {
  loop {
    match self.next {
      case Some(v) -> if func.call(v) { return Option.Some(v) }
      case _ -> return Option.None
    }
  }
}
fn pub mut find(func: fn (ref T) -> Bool) -> Option[T]

Returns the first value for which the supplied Block returns true.

This method will advance the Iter until either a value is found or we run out of values.

Examples

Finding the first number greated than 50 in an Array:

let numbers = [10, 20, 50, 80]

numbers.iter.find fn (number) { number > 50 } # => 80

find_map

Show source code
Hide source code
fn pub mut find_map[R](func: fn (T) -> Option[R]) -> Option[R] {
  loop {
    match self.next {
      case Some(v) -> {
        match func.call(v) {
          case Some(r) -> return Option.Some(r)
          case _ -> {}
        }
      }
      case _ -> return Option.None
    }
  }
}
fn pub mut find_map[R](func: fn (T) -> Option[R]) -> Option[R]

Returns an Iter that combines find with map.

For each value in self, the supplied closure is called. If the closure returns a Some, the value is returned an iteration stops.

Examples

let vals = [10, 20, 30]
let val = vals.into_iter.find_map fn (v) {
  if v == 20 { Option.Some(v.to_string) } else { Option.None }
}

val # => Option.Some('20')

headers

Show source code
Hide source code
fn pub mut headers -> Result[Map[String, Int], Error] {
  let map = Map.new
  let mut i = 0

  while try column? { map.set(try column, i := i + 1) }

  try next_line
  Result.Ok(map)
}
fn pub mut headers -> Result[Map[String, Int], Error]

Parses the current line as a list of headers and their corresponding column indexes.

Errors

This method returns an Error if parsing a column or advancing to the next line fails.

Examples

import std.csv (Parser)
import std.io (Buffer)

let parser = Parser.new(Buffer.new('foo,bar'))
let headers = parser.headers.or_panic('failed to parse the headers')

headers.get('foo') # => 0
headers.get('bar') # => 1

last

Show source code
Hide source code
fn pub move last -> Option[T] {
  reduce(Option.None, fn (_, val) { Option.Some(val) })
}
fn pub move last -> Option[T]

Returns the last value produced by this iterator.

Examples

[1, 2, 3].iter.last # => Option.Some(3)

map

Show source code
Hide source code
fn pub move map[R](func: fn (T) -> R) -> Stream[R] {
  Stream.new(fn move { self.next.map(fn (v) { func.call(v) }) })
}
fn pub move map[R](func: fn (T) -> R) -> Stream[R]

Returns an Iter that transforms values of type T to values of type R.

Examples

Multiplying the numbers in an Array:

let values = [1, 2, 3]

values.iter.map fn (n) { n * 2 }.to_array # => [2, 4, 6]

next

Show source code
Hide source code
fn pub mut next -> Option[Result[Array[String], Error]] {
  let mut cols = []

  loop {
    loop {
      match column? {
        case Ok(true) -> {
          match column {
            case Ok(v) -> cols.push(v)
            case Error(e) -> return Option.Some(Result.Error(e))
          }
        }
        case Ok(false) -> break
        case Error(e) -> return Option.Some(Result.Error(e))
      }
    }

    match next_line {
      case Ok(false) if cols.empty? -> return Option.None
      case Ok(true) if cols.empty? -> {}
      case Ok(_) -> return Option.Some(Result.Ok(cols))
      case Error(e) -> return Option.Some(Result.Error(e))
    }
  }
}
fn pub mut next -> Option[Result[Array[String], Error]]

Parses the current line as an Array of String values.

This method skips empty lines rather than returning a Option.Some(Result.Ok([])).

Errors

This method returns an Option.Some(Result.Error(Error)) if parsing the data on a line fails. Refer to the documentation of Parser.column? and Parser.column for more details.

Examples

import std.csv (Parser)
import std.io (Buffer)

let parser = Parser.new(Buffer.new('a,b\n\nc,d'))

parser.to_array # => [Result.Ok(['a', 'b']), Result.Ok(['c', 'd'])]

next_line

Show source code
Hide source code
fn pub mut next_line -> Result[Bool, Error] {
  match try peek {
    case Some(CR) -> {
      try read_byte
      try require_newline
    }
    case Some(LF) -> try read_byte
    case Some(_) -> throw error(ErrorKind.UnexpectedCharacter)
    case None -> return Result.Ok(false)
  }

  match try peek {
    case Some(_) -> Result.Ok(true)
    case None -> {
      try read_byte
      Result.Ok(false)
    }
  }
}
fn pub mut next_line -> Result[Bool, Error]

Advances the cursor to the start of the next line.

This method must be called at the end of each line in order to allow parsing of the next line.

If the next line may contain more data to parse, this method returns Result.Ok(true), otherwise it returns Result.Ok(false).

Errors

This method returns an Error if the current byte is not a cariage return ("\r") or a newline ("\n").

Examples

import std.csv (Parser)
import std.io (Buffer)

let parser = Parser.new(Buffer.new('\nfoo,bar'))

parser.next_line # => Result.Ok(true)

offset

Show source code
Hide source code
fn pub offset -> Int {
  @offset
}
fn pub offset -> Int

Returns the current byte offset of the underlying stream.

partition

Show source code
Hide source code
fn pub move partition(func: fn (ref T) -> Bool) -> (Array[T], Array[T]) {
  reduce(([], []), fn move (acc, val) {
    if func.call(ref val) { acc.0.push(val) } else { acc.1.push(val) }

    acc
  })
}
fn pub move partition(func: fn (ref T) -> Bool) -> (Array[T], Array[T])

Partitions the Iter into a tuple of two Array objects.

The first value of the tuple contains all values for which the supplied func returned true. The second value contains all values for which the func returned false.

Examples

Partitioning an Iter:

let values = [10, 20, 30, 40, 50]
let pair = values.iter.partition fn (value) { value >= 30 }

pair.0 # => [30, 40, 50]
pair.1 # => [10, 20]

peekable

Show source code
Hide source code
fn pub move peekable -> Peekable[T] {
  Peekable(iter: self, peeked: Option.None)
}
fn pub move peekable -> Peekable[T]

Returns an iterator that allows looking at the next element of the iterator, without consuming it.

Examples

let vals = [1, 2, 3]
let iter = vals.iter.peekable

iter.peek # => Option.Some(1)
iter.peek # => Option.Some(1)
iter.next # => Option.Some(1)
iter.next # => Option.Some(2)

reduce

Show source code
Hide source code
fn pub move reduce[A](accumulator: A, func: fn (A, T) -> A) -> A {
  let mut result = accumulator

  loop {
    match self.next {
      case Some(v) -> result = func.call(result, v)
      case _ -> return result
    }
  }
}
fn pub move reduce[A](accumulator: A, func: fn (A, T) -> A) -> A

Combines all values in the iterator into the specified accumulator.

This method takes two arguments:

  1. An accumulator to combine all values into.

2. A func that accepts two arguments: the accumulator and the current value.

The func returns the accumulator to return for the next value. The return value of this method is the final accumulator.

This method is called inject or fold in other languages.

Examples

Summing all integers in an iterator:

let total = [1, 2, 3].iter.reduce(0) fn (total, current) {
  total + current
}

total # => 6

At each step of the iteration, the total and current func arguments are set to the following values:

ElementTotalCurrentReturn value
0011
1123
2336

For the last element the return value is 6, so the return value of the reduce method is also 6.

select

Show source code
Hide source code
fn pub move select(func: fn (ref T) -> Bool) -> Stream[T] {
  Stream.new(fn move {
    loop {
      match self.next {
        case Some(v) -> if func.call(v) { return Option.Some(v) }
        case _ -> return Option.None
      }
    }
  })
}
fn pub move select(func: fn (ref T) -> Bool) -> Stream[T]

Returns an Iter that only produces values for which the supplied func returned true.

Examples

Selecting only certain values in an Iter:

[10, 20, 30]
  .iter
  .select fn (value) { value > 10 }
  .to_array # => [20, 30]

select_map

Show source code
Hide source code
fn pub move select_map[R](func: fn (T) -> Option[R]) -> Stream[R] {
  Stream.new(fn move {
    loop {
      match self.next {
        case Some(v) -> {
          match func.call(v) {
            case Some(r) -> return Option.Some(r)
            case _ -> next
          }
        }
        case _ -> return Option.None
      }
    }
  })
}
fn pub move select_map[R](func: fn (T) -> Option[R]) -> Stream[R]

Returns an Iter that both filters and maps at the same time.

The new iterator yields the values for which the provided func returned a Some value.

Examples

let vals = [Option.Some(10), Option.None, Option.som(30)]
let iter = vals.into_iter.select_map fn (opt) { opt }

iter.next # => Option.Some(10)
iter.next # => Option.Some(30)
iter.next # => Option.None

separator=

Show source code
Hide source code
fn pub mut separator=(separator: ref Separator) {
  @separator = separator.to_int
}
fn pub mut separator=(separator: ref Separator)

Changes the separator to use for separating columns to the given Separator.

Examples

import std.csv (Separator, Parser)
import std.io (Buffer)

let parser = Parser.new(Buffer.new('foo,bar,baz'))

parser.separator = Separator.Tab

skip

Show source code
Hide source code
fn pub move skip(amount: Int) -> Stream[T] {
  let mut pending = amount

  Stream.new(fn move {
    while pending > 0 {
      match self.next {
        case Some(_) -> pending -= 1
        case _ -> break
      }
    }

    self.next
  })
}
fn pub move skip(amount: Int) -> Stream[T]

Returns a new iterator that skips the first amount values yielded, then yields any remaining values.

The first time next is called on the returned iterator, the iterator is advanced amount times. The new iterator yields a None if there are fewer than amount items in the iterator.

Examples

[1, 2, 3].into_iter.skip(1).to_array # => [2, 3]
[1].into_iter.skip(10).to_array      # => []

skip_column

Show source code
Hide source code
fn pub mut skip_column -> Result[Nil, Error] {
  try read_column
  @buffer.clear
  Result.Ok(nil)
}
fn pub mut skip_column -> Result[Nil, Error]

Parses a single column and discards its value.

Unlike Parser.column, this method doesn't allocate a String, making it a little more efficient when skipping over large or many columns.

Errors

This method returns an Error for cases such as:

  • Reading data from the underlying stream fails
  • No more columns remain
  • The column format is invalid

Examples

import std.csv (Parser)
import std.io (Buffer)

let parser = Parser.new(Buffer.new('foo,bar'))

parser.skip_column # => Result.Ok(nil)
parser.column      # => Result.Ok('bar')

skip_columns

Show source code
Hide source code
fn pub mut skip_columns(amount: Int) -> Result[Nil, Error] {
  let mut i = 0

  while (i := i + 1) < amount { try skip_column }

  Result.Ok(nil)
}
fn pub mut skip_columns(amount: Int) -> Result[Nil, Error]

Parses and discards the values of multiple columns.

This method calls Parser.skip_column in a loop amount times, so refer to its documentation for more details.

Errors

This method returns an Error if skipping one of the columns fails. Refer to the documentation of Parser.skip_column for more details.

Examples

import std.csv (Parser)
import std.io (Buffer)

let parser = Parser.new(Buffer.new('foo,bar,baz'))

parser.skip_columns(2) # => Result.Ok(nil)
parser.column          # => Result.Ok('baz')

skip_line

Show source code
Hide source code
fn pub mut skip_line -> Result[Nil, Error] {
  loop {
    match try read_byte {
      case Some(LF) -> break
      case Some(_) -> {}
      case None -> break
    }
  }

  Result.Ok(nil)
}
fn pub mut skip_line -> Result[Nil, Error]

Skips all (remaining) data on the current line and moves the cursor to the start of the next line.

Errors

This method returns an Error if the data can't be read from the underlying stream.

Examples

import std.csv (Parser)
import std.io (Buffer)

let parser = Parser.new(Buffer.new('foo,bar'))

parser.skip_line # => Result.Ok(nil)

skip_while

Show source code
Hide source code
fn pub move skip_while(func: fn (ref T) -> Bool) -> Stream[T] {
  let mut skip = true

  Stream.new(fn move {
    while skip {
      match self.next {
        case Some(v) if func.call(v) -> {}
        case Some(v) -> {
          skip = false
          return Option.Some(v)
        }
        case _ -> return Option.None
      }
    }

    self.next
  })
}
fn pub move skip_while(func: fn (ref T) -> Bool) -> Stream[T]

Returns a new iterator that skips values for which func returns true.

Once func returns false, the remaining values in the iterator are yielded, and func is no longer called.

Examples

[1, 2, 3].into_iter.skip_while fn (v) { v <= 2 }.to_array # => [3]

take

Show source code
Hide source code
fn pub move take(amount: Int) -> Stream[T] {
  let mut pending = amount

  Stream.new(fn move {
    if (pending := pending - 1) > 0 { self.next } else { Option.None }
  })
}
fn pub move take(amount: Int) -> Stream[T]

Returns a new iterator that yields the first amount items, or fewer if amount is greater than the number of values in the iterator.

Examples

[1, 2, 3].into_iter.take(2).to_array # => [1, 2]
[1].into_iter.take(2).to_array       # => [1]

take_while

Show source code
Hide source code
fn pub move take_while(func: fn (ref T) -> Bool) -> Stream[T] {
  let mut take = true

  Stream.new(fn move {
    if take {
      match self.next {
        case Some(v) if func.call(v) -> Option.Some(v)
        case Some(_) -> {
          take = false
          Option.None
        }
        case _ -> Option.None
      }
    } else {
      Option.None
    }
  })
}
fn pub move take_while(func: fn (ref T) -> Bool) -> Stream[T]

Returns a new iterator that yields values for which func returns true.

When func returns false, any remaining values in the iterator are ignored and the iterator is no longer advanced.

Examples

[1, 2, 3].into_iter.take_while fn (v) { v <= 2 }.to_array # => [1, 2]

to_array

Show source code
Hide source code
fn pub move to_array -> Array[T] {
  reduce([], fn (values, value) {
    values.push(value)
    values
  })
}
fn pub move to_array -> Array[T]

Collects all values in the Iter in an Array.

This method will advance the iterator to the end.

Examples

Transforming an Iter back into an Array:

[1, 2, 3].iter.to_array # => [1, 2, 3]

try_each

Show source code
Hide source code
fn pub mut try_each[E](func: fn (T) -> Result[Nil, E]) -> Result[Nil, E] {
  loop {
    match self.next {
      case Some(v) -> try func.call(v)
      case _ -> return Result.Ok(nil)
    }
  }
}
fn pub mut try_each[E](func: fn (T) -> Result[Nil, E]) -> Result[Nil, E]

Calls the closure for every value in self, stopping at the first Error returned by the closure.

Examples

let res = [10, 0, 30].into_iter.try_each fn (val) {
  if val > 0 { Result.Ok(nil) } else { Result.Error('test') }
}

res # => Result.Error('test')

try_reduce

Show source code
Hide source code
fn pub mut try_reduce[A, E](
  accumulator: A,
  func: fn (A, T) -> Result[A, E],
) -> Result[A, E] {
  let mut result = accumulator

  loop {
    match self.next {
      case Some(v) -> result = try func.call(result, v)
      case _ -> return Result.Ok(result)
    }
  }
}
fn pub mut try_reduce[A, E](accumulator: A, func: fn (A, T) -> Result[A, E]) -> Result[A, E]

Combines all values in the iterator into the specified accumulator, stopping at the first Error that is encountered.

This method is similar to Iter.reduce, except the given closure is expected to return a Result wrapping the accumulator. If the return value is an Ok, iteration continues. If the return value is an Error, iteration stops and the Error is returned.

Examples

let iter = [Result.Ok(1), Result.Error('test'), Result.Ok(2)].into_iter
let result = iter.try_reduce(0) fn (acc, val) {
  match val {
    case Ok(val) -> Result.Ok(acc + val)
    case err -> err
  }
}

result # => Result.Error('test')

with_index

Show source code
Hide source code
fn pub move with_index -> Stream[(Int, T)] {
  let mut index = 0

  map(fn move (val) { (index := index + 1, val) })
}
fn pub move with_index -> Stream[(Int, T)]

Returns an Iter that yields a tuple of the index and the iterator value.

Examples

let iter = [10, 20].into_iter.with_index

iter.next # => Option.Some((0, 10))
iter.next # => Option.Some((1, 20))

zip

Show source code
Hide source code
fn pub move zip[U, I: mut + Iter[U]](other: I) -> Stream[(T, U)] {
  Stream.new(fn move { self.next.zip(other.next) })
}
fn pub move zip[U, I: mut + Iter[U]](other: I: mut) -> Stream[(T, U)]

Zips two Iter objects together, producing a new Iter that produces a tuple containing the values of both Iter objects.

The returned Iter stops iterating when one of the two zipped Iter objects runs out of values.

Examples

Zipping two Iter objects together:

let a = [10, 20, 30]
let b = [40, 50, 60]
let zip = a.iter.zip(b.iter)

zip.next # => (10, 40)

Zipping two Iter objects with a different number of values:

let a = [10, 20, 30]
let b = [40, 50]
let zip = a.iter.zip(b.iter)

zip.next # => (10, 40)

Implemented traits

std.iter.

Iter

impl Iter[Result[Array[String], Error]] for Parser