1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-17 19:22:28 +08:00

Compare commits

..

8 Commits

Author SHA1 Message Date
dudaodong
c53d541a6b doc: add document for stream package 2023-04-05 20:17:41 +08:00
dudaodong
5b9b4c4344 test: add example for stream package 2023-04-05 18:52:27 +08:00
dudaodong
6e7300bbbf feat: add CurrentPath 2023-04-05 15:55:55 +08:00
dudaodong
3685aee02b fix: fix bug of Comma function 2023-04-05 14:26:42 +08:00
dudaodong
046f3e0bf9 feat: add IsInt, IsFloat, IsNumber 2023-04-05 14:07:23 +08:00
dudaodong
c01c9d14b4 feat: add ReduceRight 2023-04-04 17:54:54 +08:00
dudaodong
f198191063 feat: add ReduceBy 2023-04-04 17:41:37 +08:00
dudaodong
8bdd46bda4 doc: add play ground demo 2023-04-03 10:33:57 +08:00
24 changed files with 2763 additions and 69 deletions

View File

@@ -711,12 +711,16 @@ import "github.com/duke-git/lancet/v2/mathutil"
[[play](https://go.dev/play/p/akLWz0EqOSM)]
- **<big>AngleToRadian</big>** : converts angle value to radian value.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#AngleToRadian)]
[[play](https://go.dev/play/p/CIvlICqrHql)]
- **<big>RadianToAngle</big>** : converts radian value to angle value.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#RadianToAngle)]
[[play](https://go.dev/play/p/dQtmOTUOMgi)]
- **<big>PointDistance</big>** : get two points distance.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#PointDistance)]
[[play](https://go.dev/play/p/RrG4JIaziM8)]
- **<big>IsPrime</big>** : checks if number is prime number.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil.md#IsPrime)]
[[play](https://go.dev/play/p/Rdd8UTHZJ7u)]
### 13. Netutil package contains functions to get net information and send http request.
@@ -1150,6 +1154,8 @@ import "github.com/duke-git/lancet/v2/strutil"
[[play](https://go.dev/play/p/bj7_odx3vRf)]
- **<big>RemoveNonPrintable</big>** : remove non-printable characters from a string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil.md#RemoveNonPrintable)]
[[play](https://go.dev/play/p/og47F5x_jTZ)]
### 19. System package contain some functions about os, runtime, shell command.
@@ -1281,8 +1287,10 @@ import "github.com/duke-git/lancet/v2/validator"
[[play](https://go.dev/play/p/E2nt3unlmzP)]
- **<big>IsASCII</big>** : checks if string is all ASCII char.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsASCII)]
[[play](https://go.dev/play/p/hfQNPLX0jNa)]
- **<big>IsPrintable</big>** : checks if string is all printable chars.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsPrintable)]
[[play](https://go.dev/play/p/Pe1FE2gdtTP)]
### 21. xerror package implements helpers for errors.

View File

@@ -710,12 +710,16 @@ import "github.com/duke-git/lancet/v2/mathutil"
[[play](https://go.dev/play/p/akLWz0EqOSM)]
- **<big>AngleToRadian</big>** : 将角度值转为弧度值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#AngleToRadian)]
[[play](https://go.dev/play/p/CIvlICqrHql)]
- **<big>RadianToAngle</big>** : 将弧度值转为角度值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#RadianToAngle)]
[[play](https://go.dev/play/p/dQtmOTUOMgi)]
- **<big>PointDistance</big>** : 计算两个坐标点的距离。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#PointDistance)]
[[play](https://go.dev/play/p/RrG4JIaziM8)]
- **<big>IsPrime</big>** : 判断质数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/mathutil_zh-CN.md#IsPrime)]
[[play](https://go.dev/play/p/Rdd8UTHZJ7u)]
### 13. netutil 网络包支持获取 ip 地址,发送 http 请求。
@@ -1152,6 +1156,7 @@ import "github.com/duke-git/lancet/v2/strutil"
[[play](https://go.dev/play/p/bj7_odx3vRf)]
- **<big>RemoveNonPrintable</big>** : 删除字符串中不可打印的字符。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/strutil_zh-CN.md#RemoveNonPrintable)]
[[play](https://go.dev/play/p/og47F5x_jTZ)]
### 19. system 包含 os, runtime, shell command 的相关函数。
@@ -1283,8 +1288,10 @@ import "github.com/duke-git/lancet/v2/validator"
[[play](https://go.dev/play/p/E2nt3unlmzP)]
- **<big>IsASCII</big>** : 验证字符串全部为 ASCII 字符。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsASCII)]
[[play](https://go.dev/play/p/hfQNPLX0jNa)]
- **<big>IsPrintable</big>** : 检查字符串是否全部为可打印字符。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsPrintable)]
[[play](https://go.dev/play/p/Pe1FE2gdtTP)]
### 21. xerror 包实现一些错误处理函数

View File

@@ -26,6 +26,7 @@ import (
- [CreateFile](#CreateFile)
- [CreateDir](#CreateDir)
- [CopyFile](#CopyFile)
- [CurrentPath](#CurrentPath)
- [FileMode](#FileMode)
- [MiMeType](#MiMeType)
- [IsExist](#IsExist)
@@ -151,6 +152,32 @@ func main() {
}
```
### <span id="CurrentPath">CurrentPath</span>
<p>return current absolute path.</p>
<b>Signature:</b>
```go
func CurrentPath() string
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
absPath := CurrentPath()
fmt.Println(absPath)
}
```
### <span id="FileMode">FileMode</span>
<p>Return file mode infomation.</p>

View File

@@ -26,6 +26,7 @@ import (
- [CreateFile](#CreateFile)
- [CreateDir](#CreateDir)
- [CopyFile](#CopyFile)
- [CurrentPath](#CurrentPath)
- [FileMode](#FileMode)
- [MiMeType](#MiMeType)
- [IsExist](#IsExist)
@@ -150,6 +151,32 @@ func main() {
}
```
### <span id="CurrentPath">CurrentPath</span>
<p>返回当前位置的绝对路径。</p>
<b>函数签名:</b>
```go
func CurrentPath() string
```
<b>示例:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/fileutil"
)
func main() {
absPath := CurrentPath()
fmt.Println(absPath)
}
```
### <span id="FileMode">FileMode</span>
<p>获取文件mode信息</p>

View File

@@ -63,6 +63,8 @@ import (
- [Merge](#Merge)
- [Reverse](#Reverse)
- [Reduce](#Reduce)
- [ReduceBy](#ReduceBy)
- [ReduceRight](#ReduceRight)
- [Replace](#Replace)
- [ReplaceAll](#ReplaceAll)
- [Repeat](#Repeat)
@@ -1504,6 +1506,72 @@ func main() {
}
```
### <span id="ReduceBy">ReduceBy</span>
<p>Produces a value from slice by accumulating the result of each element as passed through the reducer function.</p>
<b>Signature:</b>
```go
func ReduceBy[T any, U any](slice []T, initial U, reducer func(index int, item T, agg U) U) U
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
result1 := slice.ReduceBy([]int{1, 2, 3, 4}, 0, func(_ int, item int, agg int) int {
return agg + item
})
result2 := slice.ReduceBy([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
return agg + fmt.Sprintf("%v", item)
})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 10
// 1234
}
```
### <span id="ReduceRight">ReduceRight</span>
<p>ReduceRight is like ReduceBy, but it iterates over elements of slice from right to left.</p>
<b>Signature:</b>
```go
func ReduceRight[T any, U any](slice []T, initial U, reducer func(index int, item T, agg U) U) U
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
result := slice.ReduceRight([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
return agg + fmt.Sprintf("%v", item)
})
fmt.Println(result)
// Output:
// 4321
}
```
### <span id="Replace">Replace</span>
<p>Returns a copy of the slice with the first n non-overlapping instances of old replaced by new.</p>

View File

@@ -63,6 +63,8 @@ import (
- [Merge](#Merge)
- [Reverse](#Reverse)
- [Reduce](#Reduce)
- [ReduceBy](#ReduceBy)
- [ReduceRight](#ReduceRight)
- [Replace](#Replace)
- [ReplaceAll](#ReplaceAll)
- [Repeat](#Repeat)
@@ -1505,6 +1507,72 @@ func main() {
}
```
### <span id="ReduceBy">ReduceBy</span>
<p>对切片中执行reduce操作。</p>
<b>函数签名:</b>
```go
func ReduceBy[T any, U any](slice []T, initial U, reducer func(index int, item T, agg U) U) U
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
result1 := slice.ReduceBy([]int{1, 2, 3, 4}, 0, func(_ int, item int, agg int) int {
return agg + item
})
result2 := slice.ReduceBy([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
return agg + fmt.Sprintf("%v", item)
})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 10
// 1234
}
```
### <span id="ReduceRight">ReduceRight</span>
<p>类似ReduceBy操作迭代切片元素顺序从右至左。</p>
<b>函数签名:</b>
```go
func ReduceRight[T any, U any](slice []T, initial U, reducer func(index int, item T, agg U) U) U
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
result := slice.ReduceRight([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
return agg + fmt.Sprintf("%v", item)
})
fmt.Println(result)
// Output:
// 4321
}
```
### <span id="Replace">Replace</span>
<p>返回切片的副本其中前n个不重叠的old替换为new</p>

907
docs/stream.md Normal file
View File

@@ -0,0 +1,907 @@
# Stream
Package stream implements a sequence of elements supporting sequential and operations. This package is an experiment to explore if stream in go can work as the way java does. it's feature is very limited.
<div STYLE="page-break-after: always;"></div>
## Source:
- [https://github.com/duke-git/lancet/blob/main/stream/stream.go](https://github.com/duke-git/lancet/blob/main/stream/stream.go)
<div STYLE="page-break-after: always;"></div>
## Usage:
```go
import (
"github.com/duke-git/lancet/v2/stream"
)
```
<div STYLE="page-break-after: always;"></div>
## Index
- [Of](#Of)
- [FromSlice](#FromSlice)
- [FromChannel](#FromChannel)
- [FromRange](#FromRange)
- [Generate](#Generate)
- [Concat](#Concat)
- [Distinct](#Distinct)
- [Filter](#Filter)
- [Map](#Map)
- [Peek](#Peek)
- [Skip](#Skip)
- [Limit](#Limit)
- [Reverse](#Reverse)
- [Range](#Range)
- [Sorted](#Sorted)
- [ForEach](#ForEach)
- [Reduce](#Reduce)
- [FindFirst](#FindFirst)
- [Max](#Max)
- [Min](#Min)
- [AllMatch](#AllMatch)
- [AnyMatch](#AnyMatch)
- [NoneMatch](#NoneMatch)
- [Count](#Count)
- [ToSlice](#ToSlice)
<div STYLE="page-break-after: always;"></div>
## Documentation
### <span id="Of">Of</span>
<p>Creates a stream whose elements are the specified values.</p>
<b>Signature:</b>
```go
func Of[T any](elems ...T) stream[T]
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
s := stream.Of(1, 2, 3)
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3]
}
```
### <span id="FromSlice">FromSlice</span>
<p>Creates a stream from slice.</p>
<b>Signature:</b>
```go
func FromSlice[T any](source []T) stream[T]
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
s := stream.FromSlice([]int{1, 2, 3})
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3]
}
```
### <span id="FromChannel">FromChannel</span>
<p>Creates a stream from channel.</p>
<b>Signature:</b>
```go
func FromChannel[T any](source <-chan T) stream[T]
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
ch := make(chan int)
go func() {
for i := 1; i < 4; i++ {
ch <- i
}
close(ch)
}()
s := stream.FromChannel(ch)
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3]
}
```
### <span id="FromRange">FromRange</span>
<p>Creates a number stream from start to end. both start and end are included. [start, end]</p>
<b>Signature:</b>
```go
func FromRange[T constraints.Integer | constraints.Float](start, end, step T) stream[T]
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
s := stream.FromRange(1, 5, 1)
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3 4 5]
}
```
### <span id="Generate">Generate</span>
<p>Creates a stream where each element is generated by the provided generater function.</p>
<b>Signature:</b>
```go
func Generate[T any](generator func() func() (item T, ok bool)) stream[T]
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
n := 0
max := 4
generator := func() func() (int, bool) {
return func() (int, bool) {
n++
return n, n < max
}
}
s := stream.Generate(generator)
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3]
}
```
### <span id="Concat">Concat</span>
<p>Creates a lazily concatenated stream whose elements are all the elements of the first stream followed by all the elements of the second stream.</p>
<b>Signature:</b>
```go
func Concat[T any](a, b stream[T]) stream[T]
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
s1 := stream.FromSlice([]int{1, 2, 3})
s2 := stream.FromSlice([]int{4, 5, 6})
s := Concat(s1, s2)
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3 4 5 6]
}
```
### <span id="Distinct">Distinct</span>
<p>Creates returns a stream that removes the duplicated items. <b>Support chainable operation</b></p>
<b>Signature:</b>
```go
func (s stream[T]) Distinct() stream[T]
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 2, 3, 3, 3})
distinct := original.Distinct()
data1 := original.ToSlice()
data2 := distinct.ToSlice()
fmt.Println(data1)
fmt.Println(data2)
// Output:
// [1 2 2 3 3 3]
// [1 2 3]
}
```
### <span id="Filter">Filter</span>
<p>Returns a stream consisting of the elements of this stream that match the given predicate. <b>Support chainable operation</b></p>
<b>Signature:</b>
```go
func (s stream[T]) Filter(predicate func(item T) bool) stream[T]
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3, 4, 5})
isEven := func(n int) bool {
return n%2 == 0
}
even := original.Filter(isEven)
fmt.Println(even.ToSlice())
// Output:
// [2 4]
}
```
### <span id="Map">Map</span>
<p>Returns a stream consisting of the elements of this stream that apply the given function to elements of stream. <b>Support chainable operation</b></p>
<b>Signature:</b>
```go
func (s stream[T]) Map(mapper func(item T) T) stream[T]
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
addOne := func(n int) int {
return n + 1
}
increament := original.Map(addOne)
fmt.Println(increament.ToSlice())
// Output:
// [2 3 4]
}
```
### <span id="Peek">Peek</span>
<p>Returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream. <b>Support chainable operation</b></p>
<b>Signature:</b>
```go
func (s stream[T]) Peek(consumer func(item T)) stream[T]
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
data := []string{}
peekStream := original.Peek(func(n int) {
data = append(data, fmt.Sprint("value", n))
})
fmt.Println(original.ToSlice())
fmt.Println(peekStream.ToSlice())
fmt.Println(data)
// Output:
// [1 2 3]
// [1 2 3]
// [value1 value2 value3]
}
```
### <span id="Skip">Skip</span>
<p>Returns a stream consisting of the remaining elements of this stream after discarding the first n elements of the stream. If this stream contains fewer than n elements then an empty stream will be returned. <b>Support chainable operation</b></p>
<b>Signature:</b>
```go
func (s stream[T]) Skip(n int) stream[T]
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3, 4})
s1 := original.Skip(-1)
s2 := original.Skip(0)
s3 := original.Skip(1)
s4 := original.Skip(5)
fmt.Println(s1.ToSlice())
fmt.Println(s2.ToSlice())
fmt.Println(s3.ToSlice())
fmt.Println(s4.ToSlice())
// Output:
// [1 2 3 4]
// [1 2 3 4]
// [2 3 4]
// []
}
```
### <span id="Limit">Limit</span>
<p>Returns a stream consisting of the elements of this stream, truncated to be no longer than maxSize in length. <b>Support chainable operation</b></p>
<b>Signature:</b>
```go
func (s stream[T]) Limit(maxSize int) stream[T]
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3, 4})
s1 := original.Limit(-1)
s2 := original.Limit(0)
s3 := original.Limit(1)
s4 := original.Limit(5)
fmt.Println(s1.ToSlice())
fmt.Println(s2.ToSlice())
fmt.Println(s3.ToSlice())
fmt.Println(s4.ToSlice())
// Output:
// []
// []
// [1]
// [1 2 3 4]
}
```
### <span id="Reverse">Reverse</span>
<p>Returns a stream whose elements are reverse order of given stream. <b>Support chainable operation</b></p>
<b>Signature:</b>
```go
func (s stream[T]) Reverse() stream[T]
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
reverse := original.Reverse()
fmt.Println(reverse.ToSlice())
// Output:
// [3 2 1]
}
```
### <span id="Range">Range</span>
<p>Returns a stream whose elements are in the range from start(included) to end(excluded) original stream.<b>Support chainable operation</b></p>
<b>Signature:</b>
```go
func (s stream[T]) Range(start, end int) stream[T]
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
s1 := original.Range(0, 0)
s2 := original.Range(0, 1)
s3 := original.Range(0, 3)
s4 := original.Range(1, 2)
fmt.Println(s1.ToSlice())
fmt.Println(s2.ToSlice())
fmt.Println(s3.ToSlice())
fmt.Println(s4.ToSlice())
// Output:
// []
// [1]
// [1 2 3]
// [2]
}
```
### <span id="Sorted">Sorted</span>
<p>Returns a stream consisting of the elements of this stream, sorted according to the provided less function.<b>Support chainable operation</b></p>
<b>Signature:</b>
```go
func (s stream[T]) Sorted(less func(a, b T) bool) stream[T]
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{4, 2, 1, 3})
sorted := original.Sorted(func(a, b int) bool { return a < b })
fmt.Println(original.ToSlice())
fmt.Println(sorted.ToSlice())
// Output:
// [4 2 1 3]
// [1 2 3 4]
}
```
### <span id="ForEach">ForEach</span>
<p>Performs an action for each element of this stream.</p>
<b>Signature:</b>
```go
func (s stream[T]) ForEach(action func(item T))
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
result := 0
original.ForEach(func(item int) {
result += item
})
fmt.Println(result)
// Output:
// 6
}
```
### <span id="Reduce">Reduce</span>
<p>Performs a reduction on the elements of this stream, using an associative accumulation function, and returns an Optional describing the reduced value, if any.</p>
<b>Signature:</b>
```go
func (s stream[T]) Reduce(initial T, accumulator func(a, b T) T) T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
result := original.Reduce(0, func(a, b int) int {
return a + b
})
fmt.Println(result)
// Output:
// 6
}
```
### <span id="FindFirst">FindFirst</span>
<p>Returns the first element of this stream and true, or zero value and false if the stream is empty.</p>
<b>Signature:</b>
```go
func (s stream[T]) FindFirst() (T, bool)
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
result, ok := original.FindFirst()
fmt.Println(result)
fmt.Println(ok)
// Output:
// 1
// true
}
```
### <span id="Max">Max</span>
<p>Returns the maximum element of this stream according to the provided less function. less fuction: a > b</p>
<b>Signature:</b>
```go
func (s stream[T]) Max(less func(a, b T) bool) (T, bool)
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{4, 2, 1, 3})
max, ok := original.Max(func(a, b int) bool { return a > b })
fmt.Println(max)
fmt.Println(ok)
// Output:
// 4
// true
}
```
### <span id="Min">Min</span>
<p>Returns the minimum element of this stream according to the provided less function. less fuction: a < b</p>
<b>Signature:</b>
```go
func (s stream[T]) Min(less func(a, b T) bool) (T, bool)
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{4, 2, 1, 3})
min, ok := original.Min(func(a, b int) bool { return a < b })
fmt.Println(min)
fmt.Println(ok)
// Output:
// 1
// true
}
```
### <span id="AllMatch">AllMatch</span>
<p>Returns whether all elements of this stream match the provided predicate.</p>
<b>Signature:</b>
```go
func (s stream[T]) AllMatch(predicate func(item T) bool) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
result1 := original.AllMatch(func(item int) bool {
return item > 0
})
result2 := original.AllMatch(func(item int) bool {
return item > 1
})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="AnyMatch">AnyMatch</span>
<p>Returns whether any elements of this stream match the provided predicate.</p>
<b>Signature:</b>
```go
func (s stream[T]) AnyMatch(predicate func(item T) bool) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
result1 := original.AnyMatch(func(item int) bool {
return item > 1
})
result2 := original.AnyMatch(func(item int) bool {
return item > 3
})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="NoneMatch">NoneMatch</span>
<p>Returns whether no elements of this stream match the provided predicate.</p>
<b>Signature:</b>
```go
func (s stream[T]) NoneMatch(predicate func(item T) bool) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
result1 := original.NoneMatch(func(item int) bool {
return item > 3
})
result2 := original.NoneMatch(func(item int) bool {
return item > 1
})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="Count">Count</span>
<p>Returns the count of elements in the stream.</p>
<b>Signature:</b>
```go
func (s stream[T]) Count() int
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
s1 := stream.FromSlice([]int{1, 2, 3})
s2 := stream.FromSlice([]int{})
fmt.Println(s1.Count())
fmt.Println(s2.Count())
// Output:
// 3
// 0
}
```
### <span id="ToSlice">ToSlice</span>
<p>Returns the elements in the stream.</p>
<b>Signature:</b>
```go
func (s stream[T]) ToSlice() []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
s := stream.Of(1, 2, 3)
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3]
}
```

907
docs/stream_zh-CN.md Normal file
View File

@@ -0,0 +1,907 @@
# Strutil
Stream 实现,该包仅验证简单 go stream 实现,功能有限。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/stream/stream.go](https://github.com/duke-git/lancet/blob/main/stream/stream.go)
<div STYLE="page-break-after: always;"></div>
## 用法:
```go
import (
"github.com/duke-git/lancet/v2/stream"
)
```
<div STYLE="page-break-after: always;"></div>
## 目录
- [Of](#Of)
- [FromSlice](#FromSlice)
- [FromChannel](#FromChannel)
- [FromRange](#FromRange)
- [Generate](#Generate)
- [Concat](#Concat)
- [Distinct](#Distinct)
- [Filter](#Filter)
- [Map](#Map)
- [Peek](#Peek)
- [Skip](#Skip)
- [Limit](#Limit)
- [Reverse](#Reverse)
- [Range](#Range)
- [Sorted](#Sorted)
- [ForEach](#ForEach)
- [Reduce](#Reduce)
- [FindFirst](#FindFirst)
- [Max](#Max)
- [Min](#Min)
- [AllMatch](#AllMatch)
- [AnyMatch](#AnyMatch)
- [NoneMatch](#NoneMatch)
- [Count](#Count)
- [ToSlice](#ToSlice)
<div STYLE="page-break-after: always;"></div>
## 文档
### <span id="Of">Of</span>
<p>创建元素为指定值的stream。</p>
<b>函数签名:</b>
```go
func Of[T any](elems ...T) stream[T]
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
s := stream.Of(1, 2, 3)
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3]
}
```
### <span id="FromSlice">FromSlice</span>
<p>从切片创建stream。</p>
<b>函数签名:</b>
```go
func FromSlice[T any](source []T) stream[T]
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
s := stream.FromSlice([]int{1, 2, 3})
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3]
}
```
### <span id="FromChannel">FromChannel</span>
<p>从通道创建stream。</p>
<b>函数签名:</b>
```go
func FromChannel[T any](source <-chan T) stream[T]
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
ch := make(chan int)
go func() {
for i := 1; i < 4; i++ {
ch <- i
}
close(ch)
}()
s := stream.FromChannel(ch)
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3]
}
```
### <span id="FromRange">FromRange</span>
<p>指定一个范围创建stream, 范围两端点值都包括在内。</p>
<b>函数签名:</b>
```go
func FromRange[T constraints.Integer | constraints.Float](start, end, step T) stream[T]
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
s := stream.FromRange(1, 5, 1)
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3 4 5]
}
```
### <span id="Generate">Generate</span>
<p>创建一个stream其中每个元素都由提供的生成器函数生成</p>
<b>函数签名:</b>
```go
func Generate[T any](generator func() func() (item T, ok bool)) stream[T]
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
n := 0
max := 4
generator := func() func() (int, bool) {
return func() (int, bool) {
n++
return n, n < max
}
}
s := stream.Generate(generator)
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3]
}
```
### <span id="Concat">Concat</span>
<p>创建一个延迟连接stream其元素是第一个stream的所有元素后跟第二个stream的全部元素。</p>
<b>函数签名:</b>
```go
func Concat[T any](a, b stream[T]) stream[T]
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
s1 := stream.FromSlice([]int{1, 2, 3})
s2 := stream.FromSlice([]int{4, 5, 6})
s := Concat(s1, s2)
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3 4 5 6]
}
```
### <span id="Distinct">Distinct</span>
<p>创建并返回一个stream用于删除重复的项。 <b>支持链式操作</b></p>
<b>函数签名:</b>
```go
func (s stream[T]) Distinct() stream[T]
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 2, 3, 3, 3})
distinct := original.Distinct()
data1 := original.ToSlice()
data2 := distinct.ToSlice()
fmt.Println(data1)
fmt.Println(data2)
// Output:
// [1 2 2 3 3 3]
// [1 2 3]
}
```
### <span id="Filter">Filter</span>
<p>返回一个通过判定函数的stream <b>支持链式操作</b></p>
<b>函数签名:</b>
```go
func (s stream[T]) Filter(predicate func(item T) bool) stream[T]
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3, 4, 5})
isEven := func(n int) bool {
return n%2 == 0
}
even := original.Filter(isEven)
fmt.Println(even.ToSlice())
// Output:
// [2 4]
}
```
### <span id="Map">Map</span>
<p>返回一个stream该stream由将给定函数应用于源stream元素的元素组成。<b>支持链式操作</b></p>
<b>函数签名:</b>
```go
func (s stream[T]) Map(mapper func(item T) T) stream[T]
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
addOne := func(n int) int {
return n + 1
}
increament := original.Map(addOne)
fmt.Println(increament.ToSlice())
// Output:
// [2 3 4]
}
```
### <span id="Peek">Peek</span>
<p>返回一个由源stream的元素组成的stream并在从生成的stream中消耗元素时对每个元素执行所提供的操作。 <b>支持链式操作</b></p>
<b>函数签名:</b>
```go
func (s stream[T]) Peek(consumer func(item T)) stream[T]
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
data := []string{}
peekStream := original.Peek(func(n int) {
data = append(data, fmt.Sprint("value", n))
})
fmt.Println(original.ToSlice())
fmt.Println(peekStream.ToSlice())
fmt.Println(data)
// Output:
// [1 2 3]
// [1 2 3]
// [value1 value2 value3]
}
```
### <span id="Skip">Skip</span>
<p>在丢弃stream的前n个元素后返回由源stream的其余元素组成的stream。如果此stream包含的元素少于n个则将返回一个空stream。<b>支持链式操作</b></p>
<b>函数签名:</b>
```go
func (s stream[T]) Skip(n int) stream[T]
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3, 4})
s1 := original.Skip(-1)
s2 := original.Skip(0)
s3 := original.Skip(1)
s4 := original.Skip(5)
fmt.Println(s1.ToSlice())
fmt.Println(s2.ToSlice())
fmt.Println(s3.ToSlice())
fmt.Println(s4.ToSlice())
// Output:
// [1 2 3 4]
// [1 2 3 4]
// [2 3 4]
// []
}
```
### <span id="Limit">Limit</span>
<p>返回由源stream的元素组成的stream该stream被截断为长度不超过maxSize。<b>支持链式操作</b></p>
<b>函数签名:</b>
```go
func (s stream[T]) Limit(maxSize int) stream[T]
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3, 4})
s1 := original.Limit(-1)
s2 := original.Limit(0)
s3 := original.Limit(1)
s4 := original.Limit(5)
fmt.Println(s1.ToSlice())
fmt.Println(s2.ToSlice())
fmt.Println(s3.ToSlice())
fmt.Println(s4.ToSlice())
// Output:
// []
// []
// [1]
// [1 2 3 4]
}
```
### <span id="Reverse">Reverse</span>
<p>返回元素与源stream的顺序相反的stream。<b>支持链式操作</b></p>
<b>函数签名:</b>
```go
func (s stream[T]) Reverse() stream[T]
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
reverse := original.Reverse()
fmt.Println(reverse.ToSlice())
// Output:
// [3 2 1]
}
```
### <span id="Range">Range</span>
<p>返回一个stream该stream的元素在从源stream的开始包含到结束排除的范围内。<b>支持链式操作</b></p>
<b>函数签名:</b>
```go
func (s stream[T]) Range(start, end int) stream[T]
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
s1 := original.Range(0, 0)
s2 := original.Range(0, 1)
s3 := original.Range(0, 3)
s4 := original.Range(1, 2)
fmt.Println(s1.ToSlice())
fmt.Println(s2.ToSlice())
fmt.Println(s3.ToSlice())
fmt.Println(s4.ToSlice())
// Output:
// []
// [1]
// [1 2 3]
// [2]
}
```
### <span id="Sorted">Sorted</span>
<p>返回一个stream该stream由源stream的元素组成并根据提供的less函数进行排序。<b>支持链式操作</b></p>
<b>函数签名:</b>
```go
func (s stream[T]) Sorted(less func(a, b T) bool) stream[T]
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{4, 2, 1, 3})
sorted := original.Sorted(func(a, b int) bool { return a < b })
fmt.Println(original.ToSlice())
fmt.Println(sorted.ToSlice())
// Output:
// [4 2 1 3]
// [1 2 3 4]
}
```
### <span id="ForEach">ForEach</span>
<p>对stream的每个元素执行一个操作。</p>
<b>函数签名:</b>
```go
func (s stream[T]) ForEach(action func(item T))
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
result := 0
original.ForEach(func(item int) {
result += item
})
fmt.Println(result)
// Output:
// 6
}
```
### <span id="Reduce">Reduce</span>
<p>使用关联累加函数对stream的元素执行reduce操作并reduce操作结果如果有。</p>
<b>函数签名:</b>
```go
func (s stream[T]) Reduce(initial T, accumulator func(a, b T) T) T
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
result := original.Reduce(0, func(a, b int) int {
return a + b
})
fmt.Println(result)
// Output:
// 6
}
```
### <span id="FindFirst">FindFirst</span>
<p>返回此stream的第一个元素和true如果stream为空则返回零值和false。</p>
<b>函数签名:</b>
```go
func (s stream[T]) FindFirst() (T, bool)
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
result, ok := original.FindFirst()
fmt.Println(result)
fmt.Println(ok)
// Output:
// 1
// true
}
```
### <span id="Max">Max</span>
<p>根据提供的less函数返回stream的最大元素。less 函数: a > b</p>
<b>函数签名:</b>
```go
func (s stream[T]) Max(less func(a, b T) bool) (T, bool)
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{4, 2, 1, 3})
max, ok := original.Max(func(a, b int) bool { return a > b })
fmt.Println(max)
fmt.Println(ok)
// Output:
// 4
// true
}
```
### <span id="Min">Min</span>
<p>根据提供的less函数返回stream的最小元素。less函数: a < b</p>
<b>函数签名:</b>
```go
func (s stream[T]) Min(less func(a, b T) bool) (T, bool)
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{4, 2, 1, 3})
min, ok := original.Min(func(a, b int) bool { return a < b })
fmt.Println(min)
fmt.Println(ok)
// Output:
// 1
// true
}
```
### <span id="AllMatch">AllMatch</span>
<p>判断stream的所有元素是否全部匹配指定判定函数。</p>
<b>函数签名:</b>
```go
func (s stream[T]) AllMatch(predicate func(item T) bool) bool
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
result1 := original.AllMatch(func(item int) bool {
return item > 0
})
result2 := original.AllMatch(func(item int) bool {
return item > 1
})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="AnyMatch">AnyMatch</span>
<p>判断stream是否包含匹配指定判定函数的元素。</p>
<b>函数签名:</b>
```go
func (s stream[T]) AnyMatch(predicate func(item T) bool) bool
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
result1 := original.AnyMatch(func(item int) bool {
return item > 1
})
result2 := original.AnyMatch(func(item int) bool {
return item > 3
})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="NoneMatch">NoneMatch</span>
<p>判断stream的元素是否全部不匹配指定的判定函数。</p>
<b>函数签名:</b>
```go
func (s stream[T]) NoneMatch(predicate func(item T) bool) bool
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
original := stream.FromSlice([]int{1, 2, 3})
result1 := original.NoneMatch(func(item int) bool {
return item > 3
})
result2 := original.NoneMatch(func(item int) bool {
return item > 1
})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="Count">Count</span>
<p>返回stream中元素的数量。</p>
<b>函数签名:</b>
```go
func (s stream[T]) Count() int
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
s1 := stream.FromSlice([]int{1, 2, 3})
s2 := stream.FromSlice([]int{})
fmt.Println(s1.Count())
fmt.Println(s2.Count())
// Output:
// 3
// 0
}
```
### <span id="ToSlice">ToSlice</span>
<p>返回stream中的元素切片。</p>
<b>函数签名:</b>
```go
func (s stream[T]) ToSlice() []T
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/stream"
)
func main() {
s := stream.Of(1, 2, 3)
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3]
}
```

View File

@@ -15,6 +15,7 @@ import (
"os"
"path"
"path/filepath"
"runtime"
"strings"
)
@@ -345,3 +346,15 @@ func MiMeType(file any) string {
}
return mediatype
}
// CurrentPath return current absolute path.
// Play: todo
func CurrentPath() string {
var absPath string
_, filename, _, ok := runtime.Caller(1)
if ok {
absPath = path.Dir(filename)
}
return absPath
}

View File

@@ -241,3 +241,8 @@ func TestListFileNames(t *testing.T) {
expected := []string{"formatter.go", "formatter_example_test.go", "formatter_test.go"}
assert.Equal(expected, filesInPath)
}
func TestCurrentPath(t *testing.T) {
absPath := CurrentPath()
t.Log(absPath)
}

View File

@@ -6,10 +6,10 @@ package formatter
import (
"fmt"
"reflect"
"strconv"
"strings"
"github.com/duke-git/lancet/v2/convertor"
"github.com/duke-git/lancet/v2/strutil"
"github.com/duke-git/lancet/v2/validator"
"golang.org/x/exp/constraints"
)
@@ -18,54 +18,29 @@ import (
// Comma("12345", "$") => "$12,345", Comma(12345, "$") => "$12,345"
// Play: https://go.dev/play/p/eRD5k2vzUVX
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string {
s, err := numberToString(value)
if err != nil {
if validator.IsInt(value) {
v, err := convertor.ToInt(value)
if err != nil {
return ""
}
return symbol + commaInt(v)
}
if validator.IsFloat(value) {
v, err := convertor.ToFloat(value)
if err != nil {
return ""
}
return symbol + commaFloat(v)
}
if strutil.IsString(value) {
v := fmt.Sprintf("%v", value)
if validator.IsNumberStr(v) {
return symbol + commaStr(v)
}
return ""
}
dotIndex := strings.Index(s, ".")
if dotIndex != -1 {
return symbol + commaString(s[:dotIndex]) + s[dotIndex:]
}
return symbol + commaString(s)
}
func commaString(s string) string {
if len(s) <= 3 {
return s
}
return commaString(s[:len(s)-3]) + "," + commaString(s[len(s)-3:])
}
func numberToString(value any) (string, error) {
switch reflect.TypeOf(value).Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return fmt.Sprintf("%v", value), nil
// todo: need to handle 12345678.9 => 1.23456789e+07
case reflect.Float32, reflect.Float64:
return fmt.Sprintf("%v", value), nil
case reflect.String:
{
sv := fmt.Sprintf("%v", value)
if strings.Contains(sv, ".") {
_, err := strconv.ParseFloat(sv, 64)
if err != nil {
return "", err
}
return sv, nil
} else {
_, err := strconv.ParseInt(sv, 10, 64)
if err != nil {
return "", nil
}
return sv, nil
}
}
default:
return "", nil
}
return ""
}

View File

@@ -0,0 +1,85 @@
package formatter
import (
"bytes"
"math"
"strconv"
"strings"
)
// see https://github.com/dustin/go-humanize/blob/master/comma.go
func commaInt(v int64) string {
sign := ""
// Min int64 can't be negated to a usable value, so it has to be special cased.
if v == math.MinInt64 {
return "-9,223,372,036,854,775,808"
}
if v < 0 {
sign = "-"
v = 0 - v
}
parts := []string{"", "", "", "", "", "", ""}
j := len(parts) - 1
for v > 999 {
parts[j] = strconv.FormatInt(v%1000, 10)
switch len(parts[j]) {
case 2:
parts[j] = "0" + parts[j]
case 1:
parts[j] = "00" + parts[j]
}
v = v / 1000
j--
}
parts[j] = strconv.Itoa(int(v))
return sign + strings.Join(parts[j:], ",")
}
func commaFloat(v float64) string {
buf := &bytes.Buffer{}
if v < 0 {
buf.Write([]byte{'-'})
v = 0 - v
}
comma := []byte{','}
parts := strings.Split(strconv.FormatFloat(v, 'f', -1, 64), ".")
pos := 0
if len(parts[0])%3 != 0 {
pos += len(parts[0]) % 3
buf.WriteString(parts[0][:pos])
buf.Write(comma)
}
for ; pos < len(parts[0]); pos += 3 {
buf.WriteString(parts[0][pos : pos+3])
buf.Write(comma)
}
buf.Truncate(buf.Len() - 1)
if len(parts) > 1 {
buf.Write([]byte{'.'})
buf.WriteString(parts[1])
}
return buf.String()
}
func commaStr(s string) string {
dotIndex := strings.Index(s, ".")
if dotIndex != -1 {
return commaStrRecursive(s[:dotIndex]) + s[dotIndex:]
}
return commaStrRecursive(s)
}
func commaStrRecursive(s string) string {
if len(s) <= 3 {
return s
}
return commaStrRecursive(s[:len(s)-3]) + "," + commaStrRecursive(s[len(s)-3:])
}

View File

@@ -16,12 +16,13 @@ func TestComma(t *testing.T) {
assert.Equal("12,345", Comma("12345", ""))
assert.Equal("12,345.6789", Comma("12345.6789", ""))
assert.Equal("123,456,789,000", Comma("123456789000", ""))
assert.Equal("12,345,678.9", Comma("12345678.9", ""))
assert.Equal("12,345", Comma(12345, ""))
assert.Equal("$12,345", Comma(12345, "$"))
assert.Equal("¥12,345", Comma(12345, "¥"))
assert.Equal("12,345.6789", Comma(12345.6789, ""))
assert.Equal("12,345.6789", Comma(+12345.6789, ""))
// assert.Equal("12,345,678.9", Comma(12345678.9, ""))
assert.Equal("12,345,678.9", Comma(12345678.9, ""))
assert.Equal("123,456,789,000", Comma(123456789000, ""))
}

View File

@@ -218,21 +218,21 @@ func RangeWithStep[T constraints.Integer | constraints.Float](start, end, step T
}
// AngleToRadian converts angle value to radian value.
// Play: todo
// Play: https://go.dev/play/p/CIvlICqrHql
func AngleToRadian(angle float64) float64 {
radian := angle * (math.Pi / 180)
return radian
}
// RadianToAngle converts radian value to angle value.
// Play: todo
// Play: https://go.dev/play/p/dQtmOTUOMgi
func RadianToAngle(radian float64) float64 {
angle := radian * (180 / math.Pi)
return angle
}
// PointDistance get two points distance.
// Play: todo
// Play: https://go.dev/play/p/RrG4JIaziM8
func PointDistance(x1, y1, x2, y2 float64) float64 {
a := x1 - x2
b := y1 - y2
@@ -242,7 +242,7 @@ func PointDistance(x1, y1, x2, y2 float64) float64 {
}
// IsPrimes checks if number is prime number.
// Play: todo
// Play: https://go.dev/play/p/Rdd8UTHZJ7u
func IsPrime(n int) bool {
if n < 2 {
return false

View File

@@ -492,6 +492,30 @@ func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initia
return result
}
// ReduceBy produces a value from slice by accumulating the result of each element as passed through the reducer function.
// Play: todo
func ReduceBy[T any, U any](slice []T, initial U, reducer func(index int, item T, agg U) U) U {
accumulator := initial
for i, v := range slice {
accumulator = reducer(i, v, accumulator)
}
return accumulator
}
// ReduceRight is like ReduceBy, but it iterates over elements of slice from right to left.
// Play: todo
func ReduceRight[T any, U any](slice []T, initial U, reducer func(index int, item T, agg U) U) U {
accumulator := initial
for i := len(slice) - 1; i >= 0; i-- {
accumulator = reducer(i, slice[i], accumulator)
}
return accumulator
}
// Replace returns a copy of the slice with the first n non-overlapping instances of old replaced by new.
// Play: https://go.dev/play/p/P5mZp7IhOFo
func Replace[T comparable](slice []T, old T, new T, n int) []T {

View File

@@ -460,6 +460,34 @@ func ExampleReduce() {
// 6
}
func ExampleReduceBy() {
result1 := ReduceBy([]int{1, 2, 3, 4}, 0, func(_ int, item int, agg int) int {
return agg + item
})
result2 := ReduceBy([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
return agg + fmt.Sprintf("%v", item)
})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 10
// 1234
}
func ExampleReduceRight() {
result := ReduceRight([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
return agg + fmt.Sprintf("%v", item)
})
fmt.Println(result)
// Output:
// 4321
}
func ExampleReplace() {
strs := []string{"a", "b", "c", "a"}

View File

@@ -405,6 +405,32 @@ func TestReduce(t *testing.T) {
}
}
func TestReduceBy(t *testing.T) {
assert := internal.NewAssert(t, "TestReduceBy")
result1 := ReduceBy([]int{1, 2, 3, 4}, 0, func(_ int, item int, agg int) int {
return agg + item
})
result2 := ReduceBy([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
return agg + fmt.Sprintf("%v", item)
})
assert.Equal(10, result1)
assert.Equal("1234", result2)
}
func TestReduceRight(t *testing.T) {
assert := internal.NewAssert(t, "ReduceRight")
result := ReduceRight([]int{1, 2, 3, 4}, "", func(_ int, item int, agg string) string {
return agg + fmt.Sprintf("%v", item)
})
assert.Equal("4321", result)
}
func TestIntSlice(t *testing.T) {
var nums []any
nums = append(nums, 1, 2, 3)

View File

@@ -1,9 +1,8 @@
// 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 an 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 implements a sequence of elements supporting sequential and operations.
// this package is an experiment to explore if stream in go can work as the way java does. it's function is very limited.
package stream
import (
@@ -52,13 +51,14 @@ type stream[T any] struct {
source []T
}
// Of creates a stream stream whose elements are the specified values.
// Of creates a stream whose elements are the specified values.
// Play: https://go.dev/play/p/jI6_iZZuVFE
func Of[T any](elems ...T) stream[T] {
return FromSlice(elems)
}
// Generate stream where each element is generated by the provided generater function
// generater function: func() func() (item T, ok bool) {}
// Play: https://go.dev/play/p/rkOWL1yA3j9
func Generate[T any](generator func() func() (item T, ok bool)) stream[T] {
source := make([]T, 0)
@@ -75,11 +75,13 @@ func Generate[T any](generator func() func() (item T, ok bool)) stream[T] {
}
// FromSlice creates stream from slice.
// Play: https://go.dev/play/p/wywTO0XZtI4
func FromSlice[T any](source []T) stream[T] {
return stream[T]{source: source}
}
// FromChannel creates stream from channel.
// Play: https://go.dev/play/p/9TZYugGMhXZ
func FromChannel[T any](source <-chan T) stream[T] {
s := make([]T, 0)
@@ -91,6 +93,7 @@ func FromChannel[T any](source <-chan T) stream[T] {
}
// FromRange creates a number stream from start to end. both start and end are included. [start, end]
// Play: https://go.dev/play/p/9Ex1-zcg-B-
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")
@@ -109,6 +112,7 @@ func FromRange[T constraints.Integer | constraints.Float](start, end, step T) st
}
// Concat creates a lazily concatenated stream whose elements are all the elements of the first stream followed by all the elements of the second stream.
// Play: https://go.dev/play/p/HM4OlYk_OUC
func Concat[T any](a, b stream[T]) stream[T] {
source := make([]T, 0)
@@ -119,6 +123,7 @@ func Concat[T any](a, b stream[T]) stream[T] {
}
// Distinct returns a stream that removes the duplicated items.
// Play: https://go.dev/play/p/eGkOSrm64cB
func (s stream[T]) Distinct() stream[T] {
source := make([]T, 0)
@@ -147,6 +152,7 @@ func hashKey(data any) string {
}
// Filter returns a stream consisting of the elements of this stream that match the given predicate.
// Play: https://go.dev/play/p/MFlSANo-buc
func (s stream[T]) Filter(predicate func(item T) bool) stream[T] {
source := make([]T, 0)
@@ -160,6 +166,7 @@ func (s stream[T]) Filter(predicate func(item T) bool) stream[T] {
}
// Map returns a stream consisting of the elements of this stream that apply the given function to elements of stream.
// Play: https://go.dev/play/p/OtNQUImdYko
func (s stream[T]) Map(mapper func(item T) T) stream[T] {
source := make([]T, s.Count())
@@ -171,6 +178,7 @@ func (s stream[T]) Map(mapper func(item T) T) stream[T] {
}
// Peek returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream.
// Play: https://go.dev/play/p/u1VNzHs6cb2
func (s stream[T]) Peek(consumer func(item T)) stream[T] {
for _, v := range s.source {
consumer(v)
@@ -181,6 +189,7 @@ func (s stream[T]) Peek(consumer func(item T)) stream[T] {
// Skip returns a stream consisting of the remaining elements of this stream after discarding the first n elements of the stream.
// If this stream contains fewer than n elements then an empty stream will be returned.
// Play: https://go.dev/play/p/fNdHbqjahum
func (s stream[T]) Skip(n int) stream[T] {
if n <= 0 {
return s
@@ -201,6 +210,7 @@ func (s stream[T]) Skip(n int) stream[T] {
}
// Limit returns a stream consisting of the elements of this stream, truncated to be no longer than maxSize in length.
// Play: https://go.dev/play/p/qsO4aniDcGf
func (s stream[T]) Limit(maxSize int) stream[T] {
if s.source == nil {
return s
@@ -220,6 +230,7 @@ func (s stream[T]) Limit(maxSize int) stream[T] {
}
// AllMatch returns whether all elements of this stream match the provided predicate.
// Play: https://go.dev/play/p/V5TBpVRs-Cx
func (s stream[T]) AllMatch(predicate func(item T) bool) bool {
for _, v := range s.source {
if !predicate(v) {
@@ -231,6 +242,7 @@ func (s stream[T]) AllMatch(predicate func(item T) bool) bool {
}
// AnyMatch returns whether any elements of this stream match the provided predicate.
// Play: https://go.dev/play/p/PTCnWn4OxSn
func (s stream[T]) AnyMatch(predicate func(item T) bool) bool {
for _, v := range s.source {
if predicate(v) {
@@ -242,11 +254,13 @@ func (s stream[T]) AnyMatch(predicate func(item T) bool) bool {
}
// NoneMatch returns whether no elements of this stream match the provided predicate.
// Play: https://go.dev/play/p/iWS64pL1oo3
func (s stream[T]) NoneMatch(predicate func(item T) bool) bool {
return !s.AnyMatch(predicate)
}
// ForEach performs an action for each element of this stream.
// Play: https://go.dev/play/p/Dsm0fPqcidk
func (s stream[T]) ForEach(action func(item T)) {
for _, v := range s.source {
action(v)
@@ -254,20 +268,23 @@ func (s stream[T]) ForEach(action func(item T)) {
}
// Reduce performs a reduction on the elements of this stream, using an associative accumulation function, and returns an Optional describing the reduced value, if any.
func (s stream[T]) Reduce(init T, accumulator func(a, b T) T) T {
// Play: https://go.dev/play/p/6uzZjq_DJLU
func (s stream[T]) Reduce(initial T, accumulator func(a, b T) T) T {
for _, v := range s.source {
init = accumulator(init, v)
initial = accumulator(initial, v)
}
return init
return initial
}
// Count returns the count of elements in the stream.
// Play: https://go.dev/play/p/r3koY6y_Xo-
func (s stream[T]) Count() int {
return len(s.source)
}
// FindFirst returns the first element of this stream and true, or zero value and false if the stream is empty.
// Play: https://go.dev/play/p/9xEf0-6C1e3
func (s stream[T]) FindFirst() (T, bool) {
var result T
@@ -279,6 +296,7 @@ func (s stream[T]) FindFirst() (T, bool) {
}
// Reverse returns a stream whose elements are reverse order of given stream.
// Play: https://go.dev/play/p/A8_zkJnLHm4
func (s stream[T]) Reverse() stream[T] {
l := len(s.source)
source := make([]T, l)
@@ -290,6 +308,7 @@ func (s stream[T]) Reverse() stream[T] {
}
// Range returns a stream whose elements are in the range from start(included) to end(excluded) original stream.
// Play: https://go.dev/play/p/indZY5V2f4j
func (s stream[T]) Range(start, end int) stream[T] {
if start < 0 {
start = 0
@@ -315,6 +334,7 @@ func (s stream[T]) Range(start, end int) stream[T] {
}
// Sorted returns a stream consisting of the elements of this stream, sorted according to the provided less function.
// Play: https://go.dev/play/p/XXtng5uonFj
func (s stream[T]) Sorted(less func(a, b T) bool) stream[T] {
source := []T{}
source = append(source, s.source...)
@@ -326,6 +346,7 @@ func (s stream[T]) Sorted(less func(a, b T) bool) stream[T] {
// Max returns the maximum element of this stream according to the provided less function.
// less: a > b
// Play: https://go.dev/play/p/fm-1KOPtGzn
func (s stream[T]) Max(less func(a, b T) bool) (T, bool) {
var max T
@@ -343,6 +364,7 @@ func (s stream[T]) Max(less func(a, b T) bool) (T, bool) {
// Min returns the minimum element of this stream according to the provided less function.
// less: a < b
// Play: https://go.dev/play/p/vZfIDgGNRe_0
func (s stream[T]) Min(less func(a, b T) bool) (T, bool) {
var min T
@@ -360,6 +382,7 @@ func (s stream[T]) Min(less func(a, b T) bool) (T, bool) {
}
// ToSlice return the elements in the stream.
// Play: https://go.dev/play/p/jI6_iZZuVFE
func (s stream[T]) ToSlice() []T {
return s.source
}

View File

@@ -0,0 +1,373 @@
package stream
import (
"fmt"
)
func ExampleOf() {
s := Of(1, 2, 3)
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3]
}
func ExampleFromSlice() {
s := FromSlice([]int{1, 2, 3})
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3]
}
func ExampleFromChannel() {
ch := make(chan int)
go func() {
for i := 1; i < 4; i++ {
ch <- i
}
close(ch)
}()
s := FromChannel(ch)
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3]
}
func ExampleFromRange() {
s := FromRange(1, 5, 1)
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3 4 5]
}
func ExampleGenerate() {
n := 0
max := 4
generator := func() func() (int, bool) {
return func() (int, bool) {
n++
return n, n < max
}
}
s := Generate(generator)
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3]
}
func ExampleConcat() {
s1 := FromSlice([]int{1, 2, 3})
s2 := FromSlice([]int{4, 5, 6})
s := Concat(s1, s2)
data := s.ToSlice()
fmt.Println(data)
// Output:
// [1 2 3 4 5 6]
}
func ExampleStream_Distinct() {
original := FromSlice([]int{1, 2, 2, 3, 3, 3})
distinct := original.Distinct()
data1 := original.ToSlice()
data2 := distinct.ToSlice()
fmt.Println(data1)
fmt.Println(data2)
// Output:
// [1 2 2 3 3 3]
// [1 2 3]
}
func ExampleStream_Filter() {
original := FromSlice([]int{1, 2, 3, 4, 5})
isEven := func(n int) bool {
return n%2 == 0
}
even := original.Filter(isEven)
fmt.Println(even.ToSlice())
// Output:
// [2 4]
}
func ExampleStream_Map() {
original := FromSlice([]int{1, 2, 3})
addOne := func(n int) int {
return n + 1
}
increament := original.Map(addOne)
fmt.Println(increament.ToSlice())
// Output:
// [2 3 4]
}
func ExampleStream_Peek() {
original := FromSlice([]int{1, 2, 3})
data := []string{}
peekStream := original.Peek(func(n int) {
data = append(data, fmt.Sprint("value", n))
})
fmt.Println(original.ToSlice())
fmt.Println(peekStream.ToSlice())
fmt.Println(data)
// Output:
// [1 2 3]
// [1 2 3]
// [value1 value2 value3]
}
func ExampleStream_Skip() {
original := FromSlice([]int{1, 2, 3, 4})
s1 := original.Skip(-1)
s2 := original.Skip(0)
s3 := original.Skip(1)
s4 := original.Skip(5)
fmt.Println(s1.ToSlice())
fmt.Println(s2.ToSlice())
fmt.Println(s3.ToSlice())
fmt.Println(s4.ToSlice())
// Output:
// [1 2 3 4]
// [1 2 3 4]
// [2 3 4]
// []
}
func ExampleStream_Limit() {
original := FromSlice([]int{1, 2, 3, 4})
s1 := original.Limit(-1)
s2 := original.Limit(0)
s3 := original.Limit(1)
s4 := original.Limit(5)
fmt.Println(s1.ToSlice())
fmt.Println(s2.ToSlice())
fmt.Println(s3.ToSlice())
fmt.Println(s4.ToSlice())
// Output:
// []
// []
// [1]
// [1 2 3 4]
}
func ExampleStream_AllMatch() {
original := FromSlice([]int{1, 2, 3})
result1 := original.AllMatch(func(item int) bool {
return item > 0
})
result2 := original.AllMatch(func(item int) bool {
return item > 1
})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
func ExampleStream_AnyMatch() {
original := FromSlice([]int{1, 2, 3})
result1 := original.AnyMatch(func(item int) bool {
return item > 1
})
result2 := original.AnyMatch(func(item int) bool {
return item > 3
})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
func ExampleStream_NoneMatch() {
original := FromSlice([]int{1, 2, 3})
result1 := original.NoneMatch(func(item int) bool {
return item > 3
})
result2 := original.NoneMatch(func(item int) bool {
return item > 1
})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
func ExampleStream_ForEach() {
original := FromSlice([]int{1, 2, 3})
result := 0
original.ForEach(func(item int) {
result += item
})
fmt.Println(result)
// Output:
// 6
}
func ExampleStream_Reduce() {
original := FromSlice([]int{1, 2, 3})
result := original.Reduce(0, func(a, b int) int {
return a + b
})
fmt.Println(result)
// Output:
// 6
}
func ExampleStream_FindFirst() {
original := FromSlice([]int{1, 2, 3})
result, ok := original.FindFirst()
fmt.Println(result)
fmt.Println(ok)
// Output:
// 1
// true
}
func ExampleStream_Reverse() {
original := FromSlice([]int{1, 2, 3})
reverse := original.Reverse()
fmt.Println(reverse.ToSlice())
// Output:
// [3 2 1]
}
func ExampleStream_Range() {
original := FromSlice([]int{1, 2, 3})
s1 := original.Range(0, 0)
s2 := original.Range(0, 1)
s3 := original.Range(0, 3)
s4 := original.Range(1, 2)
fmt.Println(s1.ToSlice())
fmt.Println(s2.ToSlice())
fmt.Println(s3.ToSlice())
fmt.Println(s4.ToSlice())
// Output:
// []
// [1]
// [1 2 3]
// [2]
}
func ExampleStream_Sorted() {
original := FromSlice([]int{4, 2, 1, 3})
sorted := original.Sorted(func(a, b int) bool { return a < b })
fmt.Println(original.ToSlice())
fmt.Println(sorted.ToSlice())
// Output:
// [4 2 1 3]
// [1 2 3 4]
}
func ExampleStream_Max() {
original := FromSlice([]int{4, 2, 1, 3})
max, ok := original.Max(func(a, b int) bool { return a > b })
fmt.Println(max)
fmt.Println(ok)
// Output:
// 4
// true
}
func ExampleStream_Min() {
original := FromSlice([]int{4, 2, 1, 3})
min, ok := original.Min(func(a, b int) bool { return a < b })
fmt.Println(min)
fmt.Println(ok)
// Output:
// 1
// true
}
func ExampleStream_Count() {
s1 := FromSlice([]int{1, 2, 3})
s2 := FromSlice([]int{})
fmt.Println(s1.Count())
fmt.Println(s2.Count())
// Output:
// 3
// 0
}

View File

@@ -147,13 +147,17 @@ func TestStream_Peek(t *testing.T) {
func TestStream_Skip(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_Peek")
stream := FromSlice([]int{1, 2, 3, 4, 5, 6})
stream := FromSlice([]int{1, 2, 3, 4})
s1 := stream.Skip(-1)
s2 := stream.Skip(0)
s3 := stream.Skip(1)
s4 := stream.Skip(2)
assert.Equal([]int{1, 2, 3, 4, 5, 6}, s1.ToSlice())
assert.Equal([]int{1, 2, 3, 4, 5, 6}, s2.ToSlice())
assert.Equal([]int{1, 2, 3, 4}, s1.ToSlice())
assert.Equal([]int{1, 2, 3, 4}, s2.ToSlice())
assert.Equal([]int{2, 3, 4}, s3.ToSlice())
assert.Equal([]int{3, 4}, s4.ToSlice())
}
func TestStream_Limit(t *testing.T) {
@@ -248,6 +252,16 @@ func TestStream_Reduce(t *testing.T) {
assert.Equal(6, result)
}
func TestStream_Count(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_Count")
s1 := FromSlice([]int{1, 2, 3})
s2 := FromSlice([]int{})
assert.Equal(3, s1.Count())
assert.Equal(0, s2.Count())
}
func TestStream_FindFirst(t *testing.T) {
assert := internal.NewAssert(t, "TestStream_FindFirst")

View File

@@ -362,7 +362,7 @@ func WordCount(s string) int {
}
// RemoveNonPrintable remove non-printable characters from a string.
// Play: todo
// Play: https://go.dev/play/p/og47F5x_jTZ
func RemoveNonPrintable(str string) string {
result := strings.Map(func(r rune) rune {
if unicode.IsPrint(r) {

View File

@@ -59,7 +59,7 @@ func IsAllLower(str string) bool {
}
// IsASCII checks if string is all ASCII char.
// Play: todo
// Play: https://go.dev/play/p/hfQNPLX0jNa
func IsASCII(str string) bool {
for i := 0; i < len(str); i++ {
if str[i] > unicode.MaxASCII {
@@ -70,7 +70,7 @@ func IsASCII(str string) bool {
}
// IsPrintable checks if string is all printable chars.
// Play: todo
// Play: https://go.dev/play/p/Pe1FE2gdtTP
func IsPrintable(str string) bool {
for _, r := range str {
if !unicode.IsPrint(r) {
@@ -369,3 +369,29 @@ func IsGBK(data []byte) bool {
return true
}
// IsNumberStr check if the value is Number(integer, float) or not.
// Play: todo
func IsNumber(v any) bool {
return IsInt(v) || IsFloat(v)
}
// IsFloat check if the value is float(float32, float34) or not.
// Play: todo
func IsFloat(v any) bool {
switch v.(type) {
case float32, float64:
return true
}
return false
}
// IsInt check if the value is integer(int, unit) or not.
// Play: todo
func IsInt(v any) bool {
switch v.(type) {
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr:
return true
}
return false
}

View File

@@ -449,3 +449,57 @@ func ExampleIsPrintable() {
// true
// false
}
func ExampleIsInt() {
result1 := IsInt("")
result2 := IsInt("3")
result3 := IsInt(0.1)
result4 := IsInt(0)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// false
// false
// false
// true
}
func ExampleIsFloat() {
result1 := IsFloat("")
result2 := IsFloat("3")
result3 := IsFloat(0)
result4 := IsFloat(0.1)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// false
// false
// false
// true
}
func ExampleIsNumber() {
result1 := IsNumber("")
result2 := IsNumber("3")
result3 := IsNumber(0)
result4 := IsNumber(0.1)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
// Output:
// false
// false
// true
// true
}

View File

@@ -100,6 +100,34 @@ func TestIsJSON(t *testing.T) {
assert.Equal(false, IsJSON("&@#$%^&*"))
}
func TestIsNumber(t *testing.T) {
assert := internal.NewAssert(t, "TestIsNumber")
assert.Equal(false, IsNumber(""))
assert.Equal(false, IsNumber("3"))
assert.Equal(true, IsNumber(0))
assert.Equal(true, IsNumber(0.1))
}
func TestIsFloat(t *testing.T) {
assert := internal.NewAssert(t, "TestIsFloat")
assert.Equal(false, IsFloat(""))
assert.Equal(false, IsFloat("3"))
assert.Equal(false, IsFloat(0))
assert.Equal(true, IsFloat(0.1))
}
func TestIsInt(t *testing.T) {
assert := internal.NewAssert(t, "TestIsInt")
assert.Equal(false, IsInt(""))
assert.Equal(false, IsInt("3"))
assert.Equal(false, IsInt(0.1))
assert.Equal(true, IsInt(0))
assert.Equal(true, IsInt(-1))
}
func TestIsNumberStr(t *testing.T) {
assert := internal.NewAssert(t, "TestIsNumberStr")