How do I transform stream elements and take the first N in EK9?

← Streams and Pipelines · Ref: Q930

Use 'map with' to transform each element, then 'head N' to take only the first N results.

BASIC PATTERN

  cat source | map with transformer | head N | collect as List of R

The map stage applies a function to each element it is asked for, changing its type or value. The head stage stops the pull after N elements have passed through.

EXAMPLE: Transform integers to strings, take first 3

  cat [10, 20, 30, 40, 50] | map with intToLabel | head 3 | collect as List of String
  Result: ["Item-10", "Item-20", "Item-30"]

EXAMPLE: Double values, take top 2

  cat [5, 1, 8, 3] | map with doubler | head 2 > stdout
  Output: 10 then 2 (doubler runs only for 5 and 1)

Head is demand-driven: once N elements have passed, the stages before it are not asked for more, so the program here never calls doubler for 8 or 3. A stage that must see everything, such as sort, tail or join, always consumes all of its input, and a head after it only limits what it emits.

See Q235 for all operations. See Q125 for head/tail/skip details.

Example

defines module qa.streams.map.head.example

  defines function

    //Prints as it works, so the output shows how many elements map was asked for
    doubler() as pure
      -> number as Integer
      <- rtn as Integer: number * 2
      stdout <- Stdout()
      stdout.println(`doubling ${number}`)

    intToLabel() as pure
      -> number as Integer
      <- rtn as String: `Item-${number}`

  defines program

    MapHeadDemo()
      stdout <- Stdout()

      //head 2 stops the pull: doubler is never called for 8 or 3
      cat [5, 1, 8, 3]
        | map with doubler
        | head 2
        > stdout

      //Transform every element, keep the first three results
      labels <- cat [10, 20, 30, 40, 50]
        | map with intToLabel
        | head 3
        | collect as List of String
      stdout.println($labels)
Other ways to ask this
  • How does map with head work in EK9 streams?
  • Can I transform then limit results in an EK9 pipeline?
  • How do I take the first few transformed items from a stream?

Coming from another language?

Java: stream().map(fn).limit(n).collect(). Python: list(map(fn, items))[:n]. Rust: iter().map(fn).take(n).collect(). EK9: cat items | map with fn | head n | collect.

Keywords: head, stream, pipeline, first, take, limit, transform, map