From 61338b6b465f42a633cb574d72045dd9a8a51113 Mon Sep 17 00:00:00 2001 From: dudaodong Date: Tue, 17 Jan 2023 11:25:15 +0800 Subject: [PATCH] feat: add Stream package --- stream/stream.go | 75 +++++++++++++++++++++++++++++++++++++++++++ stream/stream_test.go | 25 +++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 stream/stream.go create mode 100644 stream/stream_test.go diff --git a/stream/stream.go b/stream/stream.go new file mode 100644 index 0000000..35c9d9d --- /dev/null +++ b/stream/stream.go @@ -0,0 +1,75 @@ +// Copyright 2023 dudaodong@gmail.com. All rights resulterved. +// Use of this source code is governed by MIT license + +// Package stream implements a sequence of elements supporting sequential and parallel aggregate operations. +// this package is a experiment to explore if stream in go can work as the way java does. it's complete, but not +// powerful like other libs +package stream + +import "golang.org/x/exp/constraints" + +// A stream should implements methods: +// type StreamI[T any] interface { + +// // part methods of Java Stream Specification. +// Distinct() StreamI[T] +// Filter(predicate func(item T) bool) StreamI[T] +// FlatMap(mapper func(item T) StreamI[T]) StreamI[T] +// Map(mapper func(item T) T) StreamI[T] +// Peek(consumer func(item T)) StreamI[T] + +// Sort(less func(a, b T) bool) StreamI[T] +// Max(less func(a, b T) bool) (T, bool) +// Min(less func(a, b T) bool) (T, bool) + +// Limit(maxSize int) StreamI[T] +// Skip(n int64) StreamI[T] + +// AllMatch(predicate func(item T) bool) bool +// AnyMatch(predicate func(item T) bool) bool +// NoneMatch(predicate func(item T) bool) bool +// ForEach(consumer func(item T)) +// Reduce(accumulator func(a, b T) T) (T, bool) +// Count() int + +// FindFirst() (T, bool) + +// ToSlice() []T + +// // part of methods custom extension +// Reverse() StreamI[T] +// Range(start, end int64) StreamI[T] +// Concat(streams ...StreamI[T]) StreamI[T] +// } + +type stream[T any] struct { + source []T +} + +// FromSlice create stream from slice. +func FromSlice[T any](source []T) stream[T] { + return stream[T]{source: source} +} + +// FromRange create a number stream from start to end. both start and end are included. [start, end] +func FromRange[T constraints.Integer | constraints.Float](start, end, step T) stream[T] { + if end < start { + panic("stream.FromRange: param start should be before param end") + } else if step <= 0 { + panic("stream.FromRange: param step should be positive") + } + + l := int((end-start)/step) + 1 + source := make([]T, l, l) + + for i := 0; i < l; i++ { + source[i] = start + (T(i) * step) + } + + return stream[T]{source: source} +} + +// ToSlice return the elements in the stream. +func (s stream[T]) ToSlice() []T { + return s.source +} diff --git a/stream/stream_test.go b/stream/stream_test.go new file mode 100644 index 0000000..d15dac1 --- /dev/null +++ b/stream/stream_test.go @@ -0,0 +1,25 @@ +package stream + +import ( + "testing" + + "github.com/duke-git/lancet/v2/internal" +) + +func TestFromSlice(t *testing.T) { + assert := internal.NewAssert(t, "TestFromSlice") + + stream := FromSlice([]int{1, 2, 3}) + + assert.Equal([]int{1, 2, 3}, stream.ToSlice()) +} + +func TestFromRange(t *testing.T) { + assert := internal.NewAssert(t, "TestFromSlice") + + s1 := FromRange(1, 5, 1) + s2 := FromRange(1.1, 5.0, 1.0) + + assert.Equal([]int{1, 2, 3, 4, 5}, s1.ToSlice()) + assert.Equal([]float64{1.1, 2.1, 3.1, 4.1}, s2.ToSlice()) +}