A Go library providing functional-style stream processing operations for slices. Ostinato offers a fluent API for chaining operations like map, filter, distinct, reduce, and group-by transformations.
go get github.com/cedrus-and-thuja/ostinatoOr add to your go.mod:
require github.com/cedrus-and-thuja/ostinato v0.1.0
import "github.com/cedrus-and-thuja/ostinato/pkg/ostinato"
// Create a stream from a slice
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
stream := ostinato.Stream(numbers)
// Chain operations
result := stream.
Filter(func(n int) bool { return n%2 == 0 }). // Keep even numbers
Map(func(n int) int { return n * 2 }). // Double each number
Distinct(nil) // Remove duplicates
// Convert back to slice (cast to access underlying data)
processed := result.(ostinato.Streamable[int])// Map: Transform each element (same type)
numbers := []int{1, 2, 3, 4, 5}
doubled := ostinato.Stream(numbers).
Map(func(n int) int { return n * 2 })
// MapTo: Transform elements to a different type
numbers := []int{1, 2, 3, 4, 5}
stringified := ostinato.MapTo(ostinato.Stream(numbers),
func(n int) string { return fmt.Sprintf("Number: %d", n) })
// Filter: Keep elements matching condition
even := ostinato.Stream(numbers).
Filter(func(n int) bool { return n%2 == 0 })
// Distinct: Remove duplicates
unique := ostinato.Stream([]int{1, 2, 2, 3, 3, 4}).
Distinct(nil)// Sum all numbers
numbers := []int{1, 2, 3, 4, 5}
sum := ostinato.Stream(numbers).
Reduce(func(acc any, n int) any {
return acc.(int) + n
}, 0)
// sum = 15
// Concatenate strings
words := []string{"hello", " ", "world"}
sentence := ostinato.Stream(words).
Reduce(func(acc any, word string) any {
return acc.(string) + word
}, "")
// sentence = "hello world"type Person struct {
Name string
Age int
}
people := []Person{
{Name: "Alice", Age: 25},
{Name: "Bob", Age: 45},
{Name: "Charlie", Age: 35},
{Name: "David", Age: 55},
}
// Group by age category
grouped := ostinato.Stream(people).
GroupBy(func(p Person) any {
if p.Age < 30 {
return "young"
} else if p.Age < 50 {
return "middle"
}
return "senior"
})
// Result: []Grouping[Person, any] with groups by age categorytype Product struct {
Name string
Price float64
Category string
}
products := []Product{
{Name: "Laptop", Price: 999.99, Category: "Electronics"},
{Name: "Book", Price: 15.99, Category: "Books"},
{Name: "Phone", Price: 699.99, Category: "Electronics"},
{Name: "Tablet", Price: 399.99, Category: "Electronics"},
}
// Find average price of electronics over $500
expensiveElectronics := ostinato.Stream(products).
Filter(func(p Product) bool {
return p.Category == "Electronics" && p.Price > 500
}).
Reduce(func(acc any, p Product) any {
data := acc.(map[string]float64)
data["total"] += p.Price
data["count"] += 1
return data
}, map[string]float64{"total": 0, "count": 0})
avgPrice := expensiveElectronics.(map[string]float64)["total"] /
expensiveElectronics.(map[string]float64)["count"]type Person struct {
Name string
Age int
}
type PersonDTO struct {
FullName string
AgeGroup string
}
people := []Person{
{Name: "Alice Smith", Age: 25},
{Name: "Bob Johnson", Age: 45},
{Name: "Charlie Brown", Age: 35},
{Name: "David Miller", Age: 55},
}
// Transform Person objects to PersonDTO objects
dtos := ostinato.MapTo(ostinato.Stream(people), func(p Person) PersonDTO {
ageGroup := "adult"
if p.Age < 30 {
ageGroup = "young adult"
} else if p.Age >= 50 {
ageGroup = "senior"
}
return PersonDTO{
FullName: p.Name,
AgeGroup: ageGroup,
}
})
// Further process the DTOs
filteredDTOs := dtos.Filter(func(dto PersonDTO) bool {
return dto.AgeGroup != "adult"
}).ToSlice()Stream[T](slice []T) Streamable[T]- Create a new stream from a sliceMap(fn func(T) T) Streamable[T]- Transform each element (preserves type)MapTo[T, R](s Streamable[T], fn func(T) R) Streamable[R]- Transform elements to a different typeFilter(fn FilterFunc[T]) Streamable[T]- Keep elements matching predicateDistinct(fn IdentityFunc[T, any]) Streamable[T]- Remove duplicatesReduce(fn func(any, T) any, initial any) any- Reduce to single valueGroupBy(fn func(T) any) any- Group elements by key function
MapFunc[T, R any] func(T) R- Transformation functionFilterFunc[T any] func(T) bool- Predicate functionIdentityFunc[T any, R any] func(T) R- Identity/key extraction functionReduceFunc[T, R any] func(R, T) R- Reduction function
Run tests with:
go test ./pkg/ostinato/...- Go 1.23.5 or later
This project is licensed under the MIT License.