mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-12 08:42:29 +08:00
feat: add iterator package
This commit is contained in:
104
iterator/iterator.go
Normal file
104
iterator/iterator.go
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
// Copyright 2021 dudaodong@gmail.com. All rights resulterved.
|
||||||
|
// Use of this source code is governed by MIT license
|
||||||
|
|
||||||
|
// Package iterator implements some feature of C++ STL iterators
|
||||||
|
package iterator
|
||||||
|
|
||||||
|
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
||||||
|
|
||||||
|
// Iterator is used to iterate over a slice of data.
|
||||||
|
type Iterator[T any] interface {
|
||||||
|
HasNext() bool
|
||||||
|
Next() (T, bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromSlice returns an iterator over a slice of data.
|
||||||
|
func FromSlice[T any](data []T) Iterator[T] {
|
||||||
|
// return &sliceIterator[T]{slice: data, index: 0, step: 1}
|
||||||
|
return &sliceIterator[T]{slice: data}
|
||||||
|
}
|
||||||
|
|
||||||
|
type sliceIterator[T any] struct {
|
||||||
|
slice []T
|
||||||
|
// index int
|
||||||
|
// step int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *sliceIterator[T]) HasNext() bool {
|
||||||
|
if len(iter.slice) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *sliceIterator[T]) Next() (T, bool) {
|
||||||
|
if len(iter.slice) == 0 {
|
||||||
|
var zero T
|
||||||
|
return zero, false
|
||||||
|
}
|
||||||
|
item := iter.slice[0]
|
||||||
|
iter.slice = iter.slice[1:]
|
||||||
|
return item, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count
|
||||||
|
func (iter *sliceIterator[T]) Count() int {
|
||||||
|
count := len(iter.slice)
|
||||||
|
iter.slice = []T{}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
// func (iter *sliceIterator[T]) Begin(data []T) Iterator[T] {
|
||||||
|
// iter.data = data
|
||||||
|
// iter.index = 0
|
||||||
|
// iter.step = 1
|
||||||
|
|
||||||
|
// return iter
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (iter *sliceIterator[T]) End(data []T) Iterator[T] {
|
||||||
|
// iter.data = data
|
||||||
|
// iter.index = len(data)
|
||||||
|
// iter.step = 1
|
||||||
|
|
||||||
|
// return iter
|
||||||
|
// }
|
||||||
|
|
||||||
|
// FromRange creates a iterator which returns the numeric range between start inclusive and end
|
||||||
|
// exclusive by the step size. start should be less than end, step shoud be positive.
|
||||||
|
func FromRange[T lancetconstraints.Number](start, end, step T) Iterator[T] {
|
||||||
|
if end < start {
|
||||||
|
panic("RangeIterator: start should be before end")
|
||||||
|
} else if step <= 0 {
|
||||||
|
panic("RangeIterator: step should be positive")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &rangeIterator[T]{start: start, end: end, step: step}
|
||||||
|
}
|
||||||
|
|
||||||
|
type rangeIterator[T lancetconstraints.Number] struct {
|
||||||
|
start, end, step T
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *rangeIterator[T]) HasNext() bool {
|
||||||
|
if iter.start >= iter.end {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *rangeIterator[T]) Next() (T, bool) {
|
||||||
|
if iter.start >= iter.end {
|
||||||
|
var zero T
|
||||||
|
return zero, false
|
||||||
|
}
|
||||||
|
num := iter.start
|
||||||
|
iter.start += iter.step
|
||||||
|
return num, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *rangeIterator[T]) Count() int {
|
||||||
|
count := (iter.end - iter.start) / iter.step
|
||||||
|
iter.start = iter.end
|
||||||
|
return int(count)
|
||||||
|
}
|
||||||
39
iterator/iterator_test.go
Normal file
39
iterator/iterator_test.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2021 dudaodong@gmail.com. All rights resulterved.
|
||||||
|
// Use of this source code is governed by MIT license
|
||||||
|
|
||||||
|
// Package iterator implements some feature of C++ STL iterators
|
||||||
|
package iterator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSliceIterator(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestSliceIterator")
|
||||||
|
|
||||||
|
t.Run("slice iterator has next", func(t *testing.T) {
|
||||||
|
iter := FromSlice([]int{1, 2, 3, 4})
|
||||||
|
for {
|
||||||
|
item, _ := iter.Next()
|
||||||
|
if item < 4 {
|
||||||
|
assert.Equal(true, iter.HasNext())
|
||||||
|
} else {
|
||||||
|
assert.Equal(false, iter.HasNext())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("slice iterator next", func(t *testing.T) {
|
||||||
|
iter := FromSlice([]int{1, 2, 3, 4})
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
item, ok := iter.Next()
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
assert.Equal(i+1, item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
55
iterator/operation.go
Normal file
55
iterator/operation.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// Copyright 2021 dudaodong@gmail.com. All rights resulterved.
|
||||||
|
// Use of this source code is governed by MIT license
|
||||||
|
|
||||||
|
// Package iterator implements some feature of C++ STL iterators
|
||||||
|
package iterator
|
||||||
|
|
||||||
|
// Map creates a new iterator which applies a function to all items of input iterator.
|
||||||
|
func Map[T any, U any](iter Iterator[T], iteratee func(item T) U) Iterator[U] {
|
||||||
|
return &mapIterator[T, U]{
|
||||||
|
iter: iter,
|
||||||
|
iteratee: iteratee,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type mapIterator[T any, U any] struct {
|
||||||
|
iter Iterator[T]
|
||||||
|
iteratee func(T) U
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mr *mapIterator[T, U]) HasNext() bool {
|
||||||
|
return mr.iter.HasNext()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mr *mapIterator[T, U]) Next() (U, bool) {
|
||||||
|
var zero U
|
||||||
|
item, ok := mr.iter.Next()
|
||||||
|
if !ok {
|
||||||
|
return zero, false
|
||||||
|
}
|
||||||
|
return mr.iteratee(item), true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter creates a new iterator that returns only the items that pass specified predicate function.
|
||||||
|
func Filter[T any](iter Iterator[T], predicateFunc func(item T) bool) Iterator[T] {
|
||||||
|
return &filterIterator[T]{iter: iter, predicateFunc: predicateFunc}
|
||||||
|
}
|
||||||
|
|
||||||
|
type filterIterator[T any] struct {
|
||||||
|
iter Iterator[T]
|
||||||
|
predicateFunc func(T) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fr *filterIterator[T]) Next() (T, bool) {
|
||||||
|
for item, ok := fr.iter.Next(); ok; item, ok = fr.iter.Next() {
|
||||||
|
if fr.predicateFunc(item) {
|
||||||
|
return item, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var zero T
|
||||||
|
return zero, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fr *filterIterator[T]) HasNext() bool {
|
||||||
|
return fr.iter.HasNext()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user