Skip to content
catena
v1.5.0
Theme

Slicing

Taking a window of the sequence by position or by a predicate. Take and TakeWhile consume only what they emit, so either one bounds an infinite source; TakeLast and DropLast cannot, since they have to reach the end first.

func (s Seq[T]) Take(n int) Seq[T]

Take yields at most the first n elements, consuming exactly as many as it yields. Panics if n is negative.

// The next three invoice numbers from a counter that never ends.
// Take consumes exactly what it emits, so it bounds an infinite
// source.
invoices := catena.Generate(1041, func(n int) int { return n + 1 }).
Map(func(n int) string { return fmt.Sprintf("INV-%d", n) })
fmt.Println(invoices.Take(3).Collect())
[INV-1041 INV-1042 INV-1043]
func (s Seq[T]) TakeWhile(pred func(T) bool) Seq[T]

TakeWhile yields elements until pred first returns false.

// The build steps that passed before the first failure. It stops at
// the first element that fails — unlike Filter, which would keep
// testing the rest and let "package" through.
type step struct {
Name string
Passed bool
}
steps := catena.Of(
step{"lint", true}, step{"build", true},
step{"test", false}, step{"package", true},
)
fmt.Println(steps.
TakeWhile(func(s step) bool { return s.Passed }).
Map(func(s step) string { return s.Name }).
Collect())
[lint build]
func (s Seq[T]) TakeLast(n int) Seq[T]

TakeLast yields the final n elements. Panics if n is negative.

// tail -n 2: the end of a log. It buffers only n lines, but has to
// read the source to its end to know which they are.
log := catena.Of(
"12:00:01 starting",
"12:00:02 listening on :8080",
"12:04:37 upstream timeout",
"12:04:38 shutting down",
)
log.TakeLast(2).ForEach(func(line string) { fmt.Println(line) })
12:04:37 upstream timeout
12:04:38 shutting down
func (s Seq[T]) Drop(n int) Seq[T]

Drop skips the first n elements. Panics if n is negative.

// Pagination: skip the pages already shown, then take one page.
results := catena.Of("ada", "bob", "cyd", "dee", "eve", "fay", "gus")
page, size := 1, 3
fmt.Println(results.Drop(page * size).Take(size).Collect())
[dee eve fay]
func (s Seq[T]) DropWhile(pred func(T) bool) Seq[T]

DropWhile skips elements until pred first returns false, then yields the rest.

// Skips the comment banner at the top of a config file. Only the
// leading run is dropped; once the predicate fails, everything after
// is kept — including the later comment.
config := catena.Of(
"# managed by ops",
"# do not edit",
"port = 8080",
"# seconds",
"timeout = 30",
)
fmt.Println(config.
DropWhile(func(line string) bool { return strings.HasPrefix(line, "#") }).
JoinToString("; ", catena.Self[string]))
port = 8080; # seconds; timeout = 30
func (s Seq[T]) DropLast(n int) Seq[T]

DropLast yields all but the final n elements, emitting with an n-element lag. Panics if n is negative.

// Strips a totals row off the end of an export without knowing how
// long the export is. It runs n elements behind the source, and
// buffers only those.
export := catena.Of("ada,36.00", "bob,41.50", "eve,12.25", "TOTAL,89.75")
fmt.Println(export.DropLast(1).Collect())
[ada,36.00 bob,41.50 eve,12.25]
func (s Seq[T]) Step(n int) Seq[T]

Step yields the first element and every nth element after it. Panics if n <= 0.

// Downsampling: one CPU reading in every three is enough for the
// chart. The first element always survives, then every nth after it.
cpuPercent := catena.Of(12, 15, 11, 40, 42, 38, 90, 88)
fmt.Println(cpuPercent.Step(3).Collect())
[12 40 90]