How do I use head, tail, and skip to limit streams in EK9?

← Collections and Data Structures · Ref: Q125

EK9 provides head, tail, and skip pipeline operations to control how many elements flow through a stream. These replace the need for break or early exit patterns.

HEAD N

Take only the first N elements from the stream:

  cat items | head 3 | collect as List of String

Elements after the first 3 are discarded. This is EK9's replacement for break in loops.

TAIL N

Take only the last N elements from the stream:

  cat items | tail 2 | collect as List of String

The pipeline buffers elements and only emits the final N.

SKIP N

Skip the first N elements, pass the rest:

  cat items | skip 5 | collect as List of String

Elements 1 through 5 are discarded, the rest flow through.

REPLACING BREAK WITH HEAD

Instead of a loop with break after finding enough items, use head:

  top5 <- cat allItems | sort | head 5 | collect as List of Item

This is cleaner and eliminates the bug-prone break pattern.

THE ONLY EARLY EXIT MECHANISM

EK9 has no break, return, or continue statements. Stream pipelines with head are the ONLY mechanism for efficient early exit processing in EK9. Instead of looping through a collection with a break condition, use:

  cat source | filter by predicate | head N | collect as List of T

This is not just a convenience pattern but the designed replacement for break. See Q64 for for-range loops, Q65 for for-in loops, Q66 for while loops, and Q67 for do-while loops, none of which have break.

COMBINING LIMITERS

Chain skip, head, and tail for windowing:

  cat items | skip 2 | head 3 | collect as List of String

Skip 2, then take 3 means elements 3, 4, 5 from the original.

See Q89 for basic stream pipelines. See Q120 for sort with head (top-N). See Q124 for group by with limiting. See Q145 for replacing break and continue with streams. See Q235 for complete stream operations reference. See Q237 for streams vs loops decision guide. See Q284 for find-first-match patterns. See Q287 for bounded processing with head.

Example

defines module qa.collections.headtailskip

  defines program

    HeadTailSkipDemo()
      stdout <- Stdout()

      items <- ["alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "golf"]
      stdout.println(`Original: ${items}`)

      // === HEAD N ===

      firstThree <- cat items | head 3 | collect as List of String
      stdout.println(`Head 3: ${firstThree}`)

      // === TAIL N ===

      lastTwo <- cat items | tail 2 | collect as List of String
      stdout.println(`Tail 2: ${lastTwo}`)

      // === SKIP N ===

      afterTwo <- cat items | skip 2 | collect as List of String
      stdout.println(`Skip 2: ${afterTwo}`)

      // === COMBINING: SKIP THEN HEAD ===

      // Elements 3, 4, 5 (skip 2, take 3)
      window <- cat items | skip 2 | head 3 | collect as List of String
      stdout.println(`Skip 2 head 3: ${window}`)

      // === SORT THEN HEAD (TOP-N) ===

      sorted <- cat items | sort | head 3 | collect as List of String
      stdout.println(`Top 3 sorted: ${sorted}`)

      // === DIRECT OUTPUT ===

      cat items | skip 4 > stdout

Common mistakes

E50060 — EK9 has no subList() method. Use | tail N in a stream pipeline to take the last N elements. See ek9 -h E50060 for details.

Incorrect:

lastTwo <- items.subList(items.size() - 2, items.size())

Correct:

lastTwo <- cat items | tail 2 | collect as List of String

E07560 — The head, tail, and skip operations require a positive integer (greater than zero). Zero and negative values are rejected at compile time. Use a value of 1 or greater. See ek9 -h E07560 for details.

Incorrect:

cat items | head 0 | collect as List of String

Correct:

cat items | head 3 | collect as List of String

E07830 — A supplier function used with head, tail, or skip must return Integer. A function returning Date or any non-Integer type triggers E07550. The count value must be an Integer. See ek9 -h E07550 for details.

Incorrect:

| head 3 | collect as List of Integer

Correct:

| head 3 | collect as List of String

E07560 — The head, tail, and skip operations require a positive integer (greater than zero). Zero is rejected at compile time. Use a value of 1 or greater. See ek9 -h E07560 for details.

Incorrect:

cat items | tail 0 | collect as List of String

Correct:

cat items | tail 2 | collect as List of String

E07560 — The skip operation requires a positive integer (greater than zero). Zero is rejected at compile time. Use a value of 1 or greater. See ek9 -h E07560 for details.

Incorrect:

cat items | skip 0 | head 3 | collect as List of String

Correct:

cat items | skip 2 | head 3 | collect as List of String

E07830 — The collect type must match the pipeline's element type. A String pipeline cannot collect into List of Integer because there is no pipe operator between String and Integer. See ek9 -h E07830 for details.

Incorrect:

cat items | sort | head 3 | collect as List of Integer

Correct:

cat items | sort | head 3 | collect as List of String

E07560 — Skip requires a positive integer greater than zero. Negative values like -1 are rejected at compile time. See ek9 -h E07560 for details.

Incorrect:

cat items | skip -1 > stdout

Correct:

cat items | skip 4 > stdout

E07560 — Head, tail, and skip require a positive integer greater than zero. Negative values like -1 are rejected at compile time. Use a positive count value. See ek9 -h E07560 for details.

Incorrect:

cat items | head -1 | collect as List of String

Correct:

cat items | head 3 | collect as List of String

E07560 — Head, tail, and skip require an Integer literal, not a String. Passing a string like "3" instead of the integer 3 triggers E07560. EK9 does not implicitly convert strings to integers. See ek9 -h E07560 for details.

Incorrect:

cat items | head "3" | collect as List of String

Correct:

cat items | head 3 | collect as List of String
Other ways to ask this
  • How do I take the first N items from a stream in EK9?
  • How do I skip elements in a stream pipeline in EK9?
  • What is the EK9 equivalent of break in a loop for limiting results?
  • How do I stop processing early in EK9 without break?

Coming from another language?

Java: stream.limit(n), stream.skip(n), no built-in tail. Python: itertools.islice(iter, n), list[-n:] for tail. JavaScript: array.slice(0, n) for head, array.slice(-n) for tail, array.slice(n) for skip. Rust: iter.take(n), iter.skip(n). Go: manual index slicing. EK9: | head n, | tail n, | skip n as pipeline operations, chain for windowing.

Keywords: window, pipeline, limit, early, head, replace, break, stream, last, stop, data-structure, take, first, loop, exit, collection, alternative, skip, tail