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