mirror of
https://github.com/duke-git/lancet.git
synced 2026-03-01 00:35:28 +08:00
Compare commits
8 Commits
v2.1.12
...
b07356423f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b07356423f | ||
|
|
005dd9d2ab | ||
|
|
65315dafb1 | ||
|
|
b06fb6736d | ||
|
|
b9f0854950 | ||
|
|
6a2dd328ad | ||
|
|
dd1147f6d0 | ||
|
|
6da7ce64af |
@@ -32,13 +32,13 @@ English | [简体中文](./README_zh-CN.md)
|
|||||||
|
|
||||||
### Note:
|
### Note:
|
||||||
|
|
||||||
1. <b>For users who use go1.18 and above, it is recommended to install lancet v2.x.x. Cause v2.x.x rewrite all functions with generics of go1.18.</b>
|
1. <b>For users who use go1.18 and above, it is recommended to install lancet v2.x.x. Cause in v2.x.x all functions was rewriten with generics of go1.18.</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
go get github.com/duke-git/lancet/v2 // will install latest version of v2.x.x
|
||||||
```
|
```
|
||||||
|
|
||||||
2. <b>For users who use version below go1.18, you should install v1.x.x. now latest v1 is v1.3.5. </b>
|
2. <b>For users who use version below go1.18, you should install v1.x.x. The latest of v1.x.x is v1.3.5. </b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
go get github.com/duke-git/lancet@v1.3.5 // below go1.18, install latest version of v1.x.x
|
go get github.com/duke-git/lancet@v1.3.5 // below go1.18, install latest version of v1.x.x
|
||||||
|
|||||||
@@ -31,13 +31,13 @@
|
|||||||
|
|
||||||
### Note:
|
### Note:
|
||||||
|
|
||||||
1. <b>对于使用 go1.18 及以上的用户,建议安装 v2.x.x。 因为 v2.x.x 用 go1.18 的泛型重写了大部分函数。</b>
|
1. <b>使用go1.18及以上版本的用户,建议安装v2.x.x。 因为v2.x.x应用go1.18的泛型重写了大部分函数。</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
|
go get github.com/duke-git/lancet/v2 //安装v2最新版本v2.x.x
|
||||||
```
|
```
|
||||||
|
|
||||||
2. <b>使用 go1.18 以下版本的用户,必须安装 v1.x.x。目前最新的 v1 版本是 v1.3.5。</b>
|
2. <b>使用go1.18以下版本的用户,必须安装v1.x.x。目前最新的v1版本是v1.3.5。</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
go get github.com/duke-git/lancet@v1.3.5 // 使用go1.18以下版本, 必须安装v1.x.x版本
|
go get github.com/duke-git/lancet@v1.3.5 // 使用go1.18以下版本, 必须安装v1.x.x版本
|
||||||
@@ -74,7 +74,7 @@ func main() {
|
|||||||
|
|
||||||
## [lancet API doc](https://uvdream.github.io/lancet-docs/) 感谢[@UvDream](https://github.com/UvDream)整理
|
## [lancet API doc](https://uvdream.github.io/lancet-docs/) 感谢[@UvDream](https://github.com/UvDream)整理
|
||||||
|
|
||||||
### 1. algorithm 算法包实现一些基本算法。eg. sort, search.
|
### 1. algorithm包实现一些基本查找和排序算法。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/algorithm"
|
import "github.com/duke-git/lancet/v2/algorithm"
|
||||||
@@ -95,7 +95,7 @@ import "github.com/duke-git/lancet/v2/algorithm"
|
|||||||
- [LinearSearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LinearSearch)
|
- [LinearSearch](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LinearSearch)
|
||||||
- [LRUCache](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LRUCache)
|
- [LRUCache](https://github.com/duke-git/lancet/blob/main/docs/algorithm_zh-CN.md#LRUCache)
|
||||||
|
|
||||||
### 2. concurrency 并发包包含一些支持并发编程的功能。例如:goroutine, channel, async 等。
|
### 2. concurrency包含一些支持并发编程的功能。例如:goroutine, channel, async 等。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/concurrency"
|
import "github.com/duke-git/lancet/v2/concurrency"
|
||||||
@@ -114,7 +114,7 @@ import "github.com/duke-git/lancet/v2/concurrency"
|
|||||||
- [Take](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Take)
|
- [Take](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Take)
|
||||||
- [Tee](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Tee)
|
- [Tee](https://github.com/duke-git/lancet/blob/main/docs/concurrency_zh-CN.md#Tee)
|
||||||
|
|
||||||
### 3. condition 条件包含一些用于条件判断的函数。eg. And, Or, TernaryOperator...
|
### 3. condition包含一些用于条件判断的函数。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/condition"
|
import "github.com/duke-git/lancet/v2/condition"
|
||||||
@@ -155,7 +155,7 @@ import "github.com/duke-git/lancet/v2/convertor"
|
|||||||
- [EncodeByte](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#EncodeByte)
|
- [EncodeByte](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#EncodeByte)
|
||||||
- [DecodeByte](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#DecodeByte)
|
- [DecodeByte](https://github.com/duke-git/lancet/blob/main/docs/convertor_zh-CN.md#DecodeByte)
|
||||||
|
|
||||||
### 5. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。
|
### 5. cryptor 加密包支持数据加密和解密,获取md5,hash 值。支持base64, md5, hmac, aes, des, rsa。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/cryptor"
|
import "github.com/duke-git/lancet/v2/cryptor"
|
||||||
@@ -259,7 +259,7 @@ import hashmap "github.com/duke-git/lancet/v2/datastructure/hashmap"
|
|||||||
- [Heap](https://github.com/duke-git/lancet/blob/main/docs/datastructure/heap.md)
|
- [Heap](https://github.com/duke-git/lancet/blob/main/docs/datastructure/heap.md)
|
||||||
- [HashMap](https://github.com/duke-git/lancet/blob/main/docs/datastructure/hashmap.md)
|
- [HashMap](https://github.com/duke-git/lancet/blob/main/docs/datastructure/hashmap.md)
|
||||||
|
|
||||||
### 8. fileutil 包支持文件基本操作。
|
### 8. fileutil 包含文件基本操作。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/fileutil"
|
import "github.com/duke-git/lancet/v2/fileutil"
|
||||||
@@ -310,7 +310,7 @@ import "github.com/duke-git/lancet/v2/function"
|
|||||||
- [Pipeline](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Pipeline)
|
- [Pipeline](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Pipeline)
|
||||||
- [Watcher](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)
|
- [Watcher](https://github.com/duke-git/lancet/blob/main/docs/function_zh-CN.md#Watcher)
|
||||||
|
|
||||||
### 11. maputil 包包括一些操作 map 的函数.
|
### 11. maputil包括一些操作map的函数.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/maputil"
|
import "github.com/duke-git/lancet/v2/maputil"
|
||||||
@@ -327,7 +327,7 @@ import "github.com/duke-git/lancet/v2/maputil"
|
|||||||
- [Values](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Values)
|
- [Values](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#Values)
|
||||||
- [IsDisjoint](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#IsDisjoint)
|
- [IsDisjoint](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#IsDisjoint)
|
||||||
|
|
||||||
### 12. mathutil 包实现了一些数学计算的函数。
|
### 12. mathutil包实现了一些数学计算的函数。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/mathutil"
|
import "github.com/duke-git/lancet/v2/mathutil"
|
||||||
@@ -348,7 +348,7 @@ import "github.com/duke-git/lancet/v2/mathutil"
|
|||||||
- [RoundToString](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RoundToString)
|
- [RoundToString](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RoundToString)
|
||||||
- [TruncRound](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#TruncRound)
|
- [TruncRound](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#TruncRound)
|
||||||
|
|
||||||
### 13. netutil 网络包支持获取 ip 地址,发送 http 请求。
|
### 13. netutil网络包支持获取ip地址,发送http请求。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/netutil"
|
import "github.com/duke-git/lancet/v2/netutil"
|
||||||
@@ -377,7 +377,7 @@ import "github.com/duke-git/lancet/v2/netutil"
|
|||||||
- [HttpPatch<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPatch)
|
- [HttpPatch<sup>deprecated</sup>](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#HttpPatch)
|
||||||
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ParseHttpResponse)
|
- [ParseHttpResponse](https://github.com/duke-git/lancet/blob/main/docs/netutil_zh-CN.md#ParseHttpResponse)
|
||||||
|
|
||||||
### 14. random 随机数生成器包,可以生成随机[]bytes, int, string。
|
### 14. random随机数生成器包,可以生成随机[]bytes, int, string。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/random"
|
import "github.com/duke-git/lancet/v2/random"
|
||||||
@@ -394,7 +394,7 @@ import "github.com/duke-git/lancet/v2/random"
|
|||||||
- [RandNumeralOrLetter](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandNumeralOrLetter)
|
- [RandNumeralOrLetter](https://github.com/duke-git/lancet/blob/main/docs/random_zh-CN.md#RandNumeralOrLetter)
|
||||||
- [UUIdV4](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)
|
- [UUIdV4](https://github.com/duke-git/lancet/blob/main/docs/random.md#UUIdV4)
|
||||||
|
|
||||||
### 15. retry 重试执行函数直到函数运行成功或被 context cancel。
|
### 15. retry重试执行函数直到函数运行成功或被context cancel。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/retry"
|
import "github.com/duke-git/lancet/v2/retry"
|
||||||
@@ -408,7 +408,7 @@ import "github.com/duke-git/lancet/v2/retry"
|
|||||||
- [RetryDuration](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryDuration)
|
- [RetryDuration](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryDuration)
|
||||||
- [RetryTimes](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryTimes)
|
- [RetryTimes](https://github.com/duke-git/lancet/blob/main/docs/retry_zh-CN.md#RetryTimes)
|
||||||
|
|
||||||
### 16. slice 包包含操作切片的方法集合。
|
### 16. slice包含操作切片的方法集合。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/slice"
|
import "github.com/duke-git/lancet/v2/slice"
|
||||||
@@ -468,7 +468,7 @@ import "github.com/duke-git/lancet/v2/slice"
|
|||||||
- [Without](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Without)
|
- [Without](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Without)
|
||||||
- [KeyBy](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#KeyBy)
|
- [KeyBy](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#KeyBy)
|
||||||
|
|
||||||
### 17. strutil 包含处理字符串的相关函数。
|
### 17. strutil包含处理字符串的相关函数。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/strutil"
|
import "github.com/duke-git/lancet/v2/strutil"
|
||||||
@@ -496,7 +496,7 @@ import "github.com/duke-git/lancet/v2/strutil"
|
|||||||
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Wrap)
|
- [Wrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Wrap)
|
||||||
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Unwrap)
|
- [Unwrap](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#Unwrap)
|
||||||
|
|
||||||
### 18. system 包含 os, runtime, shell command 相关函数。
|
### 18. system包含os, runtime, shell command的相关函数。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/system"
|
import "github.com/duke-git/lancet/v2/system"
|
||||||
@@ -514,7 +514,7 @@ import "github.com/duke-git/lancet/v2/system"
|
|||||||
- [ExecCommand](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#ExecCommand)
|
- [ExecCommand](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#ExecCommand)
|
||||||
- [GetOsBits](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#GetOsBits)
|
- [GetOsBits](https://github.com/duke-git/lancet/blob/main/docs/system_zh-CN.md#GetOsBits)
|
||||||
|
|
||||||
### 19. validator 验证器包,包含常用字符串格式验证函数。
|
### 19. validator验证器包,包含常用字符串格式验证函数。
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/validator"
|
import "github.com/duke-git/lancet/v2/validator"
|
||||||
@@ -551,7 +551,7 @@ import "github.com/duke-git/lancet/v2/validator"
|
|||||||
- [IsZeroValue](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsZeroValue)
|
- [IsZeroValue](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsZeroValue)
|
||||||
- [IsGBK](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsGBK)
|
- [IsGBK](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsGBK)
|
||||||
|
|
||||||
### 20. xerror 包实现一些错误处理函数
|
### 20. xerror包实现一些错误处理函数
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/duke-git/lancet/v2/xerror"
|
import "github.com/duke-git/lancet/v2/xerror"
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
package iterator
|
package iterator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"golang.org/x/exp/constraints"
|
"golang.org/x/exp/constraints"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -102,21 +104,15 @@ func (iter *sliceIterator[T]) HasNext() bool {
|
|||||||
|
|
||||||
func (iter *sliceIterator[T]) Next() (T, bool) {
|
func (iter *sliceIterator[T]) Next() (T, bool) {
|
||||||
iter.index++
|
iter.index++
|
||||||
|
|
||||||
ok := iter.index >= 0 && iter.index < len(iter.slice)
|
ok := iter.index >= 0 && iter.index < len(iter.slice)
|
||||||
|
|
||||||
var item T
|
var item T
|
||||||
if ok {
|
if ok {
|
||||||
item = iter.slice[iter.index]
|
item = iter.slice[iter.index]
|
||||||
}
|
}
|
||||||
return item, ok
|
|
||||||
|
|
||||||
// if len(iter.slice) == 0 {
|
return item, ok
|
||||||
// var zero T
|
|
||||||
// return zero, false
|
|
||||||
// }
|
|
||||||
// iter.index++
|
|
||||||
// item := iter.slice[0]
|
|
||||||
// iter.slice = iter.slice[1:]
|
|
||||||
// return item, true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prev implements PrevIterator.
|
// Prev implements PrevIterator.
|
||||||
@@ -171,3 +167,41 @@ func (iter *rangeIterator[T]) Next() (T, bool) {
|
|||||||
iter.start += iter.step
|
iter.start += iter.step
|
||||||
return num, true
|
return num, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 FromChannel[T any](channel <-chan T) Iterator[T] {
|
||||||
|
return &channelIterator[T]{channel: channel}
|
||||||
|
}
|
||||||
|
|
||||||
|
type channelIterator[T any] struct {
|
||||||
|
channel <-chan T
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *channelIterator[T]) Next() (T, bool) {
|
||||||
|
item, ok := <-iter.channel
|
||||||
|
return item, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *channelIterator[T]) HasNext() bool {
|
||||||
|
return len(iter.channel) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToChannel create a new goroutine to pull items from the channel iterator to the returned channel.
|
||||||
|
func ToChannel[T any](ctx context.Context, iter Iterator[T], buffer int) <-chan T {
|
||||||
|
result := make(chan T, buffer)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer close(result)
|
||||||
|
|
||||||
|
for item, ok := iter.Next(); ok; item, ok = iter.Next() {
|
||||||
|
select {
|
||||||
|
case result <- item:
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
package iterator
|
package iterator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/v2/internal"
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
@@ -47,4 +48,56 @@ func TestSliceIterator(t *testing.T) {
|
|||||||
assert.Equal(false, ok)
|
assert.Equal(false, ok)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("slice iterator ToSlice: ", func(t *testing.T) {
|
||||||
|
iter := FromSlice([]int{1, 2, 3, 4})
|
||||||
|
item, _ := iter.Next()
|
||||||
|
assert.Equal(1, item)
|
||||||
|
|
||||||
|
data := ToSlice(iter)
|
||||||
|
assert.Equal([]int{2, 3, 4}, data)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRangeIterator(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestRangeIterator")
|
||||||
|
|
||||||
|
t.Run("range iterator: ", func(t *testing.T) {
|
||||||
|
iter := FromRange(1, 4, 1)
|
||||||
|
|
||||||
|
item, ok := iter.Next()
|
||||||
|
assert.Equal(1, item)
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
|
||||||
|
item, ok = iter.Next()
|
||||||
|
assert.Equal(2, item)
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
|
||||||
|
item, ok = iter.Next()
|
||||||
|
assert.Equal(3, item)
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
|
||||||
|
_, ok = iter.Next()
|
||||||
|
assert.Equal(false, ok)
|
||||||
|
assert.Equal(false, iter.HasNext())
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChannelIterator(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestRangeIterator")
|
||||||
|
|
||||||
|
iter := FromSlice([]int{1, 2, 3, 4})
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
iter = FromChannel(ToChannel(ctx, iter, 0))
|
||||||
|
item, ok := iter.Next()
|
||||||
|
assert.Equal(1, item)
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
assert.Equal(true, iter.HasNext())
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
_, ok = iter.Next()
|
||||||
|
assert.Equal(false, ok)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,3 +59,81 @@ func (fr *filterIterator[T]) Next() (T, bool) {
|
|||||||
func (fr *filterIterator[T]) HasNext() bool {
|
func (fr *filterIterator[T]) HasNext() bool {
|
||||||
return fr.iter.HasNext()
|
return fr.iter.HasNext()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Join creates an iterator that join all elements of iters[0], then all elements of iters[1] and so on.
|
||||||
|
func Join[T any](iters ...Iterator[T]) Iterator[T] {
|
||||||
|
return &joinIterator[T]{
|
||||||
|
iters: iters,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type joinIterator[T any] struct {
|
||||||
|
iters []Iterator[T]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *joinIterator[T]) Next() (T, bool) {
|
||||||
|
for len(iter.iters) > 0 {
|
||||||
|
item, ok := iter.iters[0].Next()
|
||||||
|
if ok {
|
||||||
|
return item, true
|
||||||
|
}
|
||||||
|
iter.iters = iter.iters[1:]
|
||||||
|
}
|
||||||
|
var zero T
|
||||||
|
return zero, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *joinIterator[T]) HasNext() bool {
|
||||||
|
if len(iter.iters) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if len(iter.iters) == 1 {
|
||||||
|
return iter.iters[0].HasNext()
|
||||||
|
}
|
||||||
|
|
||||||
|
result := iter.iters[0].HasNext()
|
||||||
|
|
||||||
|
for i := 1; i < len(iter.iters); i++ {
|
||||||
|
it := iter.iters[i]
|
||||||
|
hasNext := it.HasNext()
|
||||||
|
result = result || hasNext
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce reduces iter to a single value using the reduction function reducer
|
||||||
|
func Reduce[T any, U any](iter Iterator[T], initial U, reducer func(U, T) U) U {
|
||||||
|
acc := initial
|
||||||
|
|
||||||
|
for item, ok := iter.Next(); ok; item, ok = iter.Next() {
|
||||||
|
acc = reducer(acc, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc
|
||||||
|
}
|
||||||
|
|
||||||
|
func Take[T any](it Iterator[T], num int) Iterator[T] {
|
||||||
|
return &takeIterator[T]{it: it, num: num}
|
||||||
|
}
|
||||||
|
|
||||||
|
type takeIterator[T any] struct {
|
||||||
|
it Iterator[T]
|
||||||
|
num int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *takeIterator[T]) Next() (T, bool) {
|
||||||
|
if iter.num <= 0 {
|
||||||
|
var zero T
|
||||||
|
return zero, false
|
||||||
|
}
|
||||||
|
item, ok := iter.it.Next()
|
||||||
|
if ok {
|
||||||
|
iter.num--
|
||||||
|
}
|
||||||
|
return item, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iter *takeIterator[T]) HasNext() bool {
|
||||||
|
return iter.num > 0
|
||||||
|
}
|
||||||
|
|||||||
73
iterator/operation_test.go
Normal file
73
iterator/operation_test.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
// Copyright 2022 dudaodong@gmail.com. All rights resulterved.
|
||||||
|
// Use of this source code is governed by MIT license
|
||||||
|
|
||||||
|
// Package iterator provides a way to iterate over values stored in containers.
|
||||||
|
// note:
|
||||||
|
// 1. Full feature iterator is complicated, this package is just a experiment to explore how iterators could work in Go.
|
||||||
|
// 2. The functionality of this package is very simple and limited, may not meet the actual dev needs.
|
||||||
|
// 3. It is currently under development, unstable, and will not be completed for some time in the future.
|
||||||
|
// So, based on above factors, you may not use it in production. but, anyone is welcome to improve it.
|
||||||
|
// Hope that Go can support iterator in future. see https://github.com/golang/go/discussions/54245 and https://github.com/golang/go/discussions/56413
|
||||||
|
package iterator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMapIterator(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestMapIterator")
|
||||||
|
|
||||||
|
iter := FromSlice([]int{1, 2, 3, 4})
|
||||||
|
|
||||||
|
iter = Map(iter, func(n int) int { return n / 2 })
|
||||||
|
|
||||||
|
result := ToSlice(iter)
|
||||||
|
assert.Equal([]int{0, 1, 1, 2}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterIterator(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestFilterIterator")
|
||||||
|
|
||||||
|
iter := FromSlice([]int{1, 2, 3, 4})
|
||||||
|
|
||||||
|
iter = Filter(iter, func(n int) bool { return n < 3 })
|
||||||
|
|
||||||
|
result := ToSlice(iter)
|
||||||
|
assert.Equal([]int{1, 2}, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJoinIterator(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestJoinIterator")
|
||||||
|
|
||||||
|
iter1 := FromSlice([]int{1, 2})
|
||||||
|
iter2 := FromSlice([]int{3, 4})
|
||||||
|
|
||||||
|
iter := Join(iter1, iter2)
|
||||||
|
|
||||||
|
item, ok := iter.Next()
|
||||||
|
assert.Equal(1, item)
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
|
||||||
|
assert.Equal([]int{2, 3, 4}, ToSlice(iter))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReduce(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestReduce")
|
||||||
|
|
||||||
|
iter := FromSlice([]int{1, 2, 3, 4})
|
||||||
|
sum := Reduce(iter, 0, func(a, b int) int { return a + b })
|
||||||
|
assert.Equal(10, sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTakeIterator(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestTakeIterator")
|
||||||
|
|
||||||
|
iter := FromSlice([]int{1, 2, 3, 4, 5})
|
||||||
|
|
||||||
|
iter = Take(iter, 3)
|
||||||
|
|
||||||
|
result := ToSlice(iter)
|
||||||
|
assert.Equal([]int{1, 2, 3}, result)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user