1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-03-01 00:35:28 +08:00

Compare commits

...

7 Commits

Author SHA1 Message Date
Honly
5d29119d1a Merge f861e18bc3 into e27df00fa8 2025-01-30 08:25:57 +00:00
Tuuuuuuuuu
e27df00fa8 make Bridge not block in the first stream that not closed (#288)
* not block in the first channel

* make Bridge not block in the first stream that not closed

* Bridge with test
2025-01-14 16:19:45 +08:00
dudaodong
a0d97cf38e Merge branch 'rc' into v2 2024-12-25 16:13:04 +08:00
残念
1f6bab467c Merge pull request #282 from Yurunsoft/fix-RandFloats
fix the bug of random.RandFloats() infinite loop and the result of random.RandFloat() sometimes equals to max.
2024-12-25 15:14:17 +08:00
Yurun
2e5b9bc200 fix: fix the bug of random.RandFloats() infinite loop and the result of random.RandFloat() sometimes equals to max. 2024-12-25 14:13:11 +08:00
dudaodong
ab89f0aee1 feat: add EqualUnordered 2024-12-19 19:36:17 +08:00
tangke
1f64e02df4 fix(fileutil): unzip Chinese garbled code during decompression (#279)
解压时出现中文乱码
2024-12-19 19:06:27 +08:00
11 changed files with 182 additions and 21 deletions

View File

@@ -157,10 +157,10 @@ func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
// Play: https://go.dev/play/p/qmWSy1NVF-Y
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T {
valStream := make(chan T)
go func() {
defer close(valStream)
wg := sync.WaitGroup{}
defer wg.Wait()
for {
var stream <-chan T
select {
@@ -169,19 +169,22 @@ func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-c
return
}
stream = maybeStream
wg.Add(1)
case <-ctx.Done():
return
}
for val := range c.OrDone(ctx, stream) {
select {
case valStream <- val:
case <-ctx.Done():
go func() {
defer wg.Done()
for val := range c.OrDone(ctx, stream) {
select {
case valStream <- val:
case <-ctx.Done():
}
}
}
}()
}
}()
return valStream
}

View File

@@ -168,7 +168,8 @@ func ExampleChannel_Tee() {
func ExampleChannel_Bridge() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
m1 := make(map[int]int)
m2 := make(map[int]int)
c := NewChannel[int]()
genVals := func() <-chan <-chan int {
out := make(chan (<-chan int))
@@ -177,6 +178,7 @@ func ExampleChannel_Bridge() {
for i := 1; i <= 5; i++ {
stream := make(chan int, 1)
stream <- i
m1[i]++
close(stream)
out <- stream
}
@@ -185,12 +187,15 @@ func ExampleChannel_Bridge() {
}
for v := range c.Bridge(ctx, genVals()) {
fmt.Println(v)
m2[v]++
}
for k, v := range m1 {
fmt.Println(m2[k] == v)
}
// Output:
// 1
// 2
// 3
// 4
// 5
// true
// true
// true
// true
// true
}

View File

@@ -169,7 +169,8 @@ func TestTee(t *testing.T) {
func TestBridge(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestBridge")
m1 := make(map[int]int)
m2 := make(map[int]int)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@@ -181,6 +182,7 @@ func TestBridge(t *testing.T) {
for i := 0; i < 10; i++ {
stream := make(chan int, 1)
stream <- i
m1[i]++
close(stream)
chanStream <- stream
}
@@ -188,9 +190,11 @@ func TestBridge(t *testing.T) {
return chanStream
}
index := 0
for val := range c.Bridge(ctx, genVals()) {
assert.Equal(index, val)
index++
m2[val]++
}
for k, v := range m1 {
assert.Equal(m2[k], v)
}
}

View File

@@ -44,6 +44,7 @@ import (
- [Every](#Every)
- [Equal](#Equal)
- [EqualWith](#EqualWith)
- [EqualUnordered](#EqualUnordered)
- [Filter](#Filter)
- [FilterConcurrent](#FilterConcurrent)
- [Find<sup>deprecated</sup>](#Find)
@@ -874,6 +875,37 @@ func main() {
}
```
### <span id="EqualUnordered">EqualUnordered</span>
<p>检查两个切片是否相等,元素数量相同,值相等,不考虑元素顺序。</p>
<b>函数签名:</b>
```go
func EqualUnordered[T comparable](slice1, slice2 []T) bool
```
<b>示例:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
result1 := slice.EqualUnordered([]int{1, 2, 3}, []int{3, 2, 1})
result2 := slice.EqualUnordered([]int{1, 2, 3}, []int{4, 5, 6})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="Filter">Filter</span>
<p>返回切片中通过predicate函数真值测试的所有元素</p>

View File

@@ -43,6 +43,7 @@ import (
- [DropRightWhile](#DropRightWhile)
- [Equal](#Equal)
- [EqualWith](#EqualWith)
- [EqualUnordered](#EqualUnordered)
- [Every](#Every)
- [Filter](#Filter)
- [FilterConcurrent](#FilterConcurrent)
@@ -839,6 +840,37 @@ func main() {
}
```
### <span id="EqualUnordered">EqualUnordered</span>
<p>Checks if two slices are equal: the same length and all elements' value are equal (unordered).</p>
<b>Signature:</b>
```go
func EqualUnordered[T comparable](slice1, slice2 []T) bool
```
<b>Example:<span style="float:right;display:inline-block;">[运行](todo)</span></b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
result1 := slice.EqualUnordered([]int{1, 2, 3}, []int{3, 2, 1})
result2 := slice.EqualUnordered([]int{1, 2, 3}, []int{4, 5, 6})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="Every">Every</span>
<p>Return true if all of the values in the slice pass the predicate function.</p>

View File

@@ -25,6 +25,8 @@ import (
"sync"
"github.com/duke-git/lancet/v2/validator"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
)
// FileReader is a reader supporting offset seeking and reading one
@@ -422,8 +424,15 @@ func UnZip(zipFile string, destPath string) error {
defer zipReader.Close()
for _, f := range zipReader.File {
decodeName := f.Name
if f.Flags == 0 {
i := bytes.NewReader([]byte(f.Name))
decoder := transform.NewReader(i, simplifiedchinese.GB18030.NewDecoder())
content, _ := io.ReadAll(decoder)
decodeName = string(content)
}
// issue#62: fix ZipSlip bug
path, err := safeFilepathJoin(destPath, f.Name)
path, err := safeFilepathJoin(destPath, decodeName)
if err != nil {
return err
}

View File

@@ -126,12 +126,24 @@ func RandFloat(min, max float64, precision int) float64 {
n := rand.Float64()*(max-min) + min
return mathutil.RoundToFloat(n, precision)
return mathutil.FloorToFloat(n, precision)
}
// RandFloats generate a slice of random float64 numbers of length that do not repeat.
// Play: https://go.dev/play/p/I3yndUQ-rhh
func RandFloats(length int, min, max float64, precision int) []float64 {
if max < min {
min, max = max, min
}
maxLength := int((max - min) * math.Pow10(precision))
if maxLength == 0 {
maxLength = 1
}
if length > maxLength {
length = maxLength
}
nums := make([]float64, length)
used := make(map[float64]struct{}, length)
for i := 0; i < length; {

View File

@@ -197,6 +197,14 @@ func TestRandFloats(t *testing.T) {
}
assert.Equal(len(numbers), 5)
numbers2 := RandFloats(10, 3.14, 3.2, 2)
for _, n := range numbers2 {
assert.GreaterOrEqual(n, 3.14)
assert.Less(n, 3.2)
}
assert.Equal(len(numbers2), 6)
}
func TestRandIntSlice(t *testing.T) {

View File

@@ -220,6 +220,28 @@ func EqualWith[T, U any](slice1 []T, slice2 []U, comparator func(T, U) bool) boo
return true
}
// EqualUnordered checks if two slices are equal: the same length and all elements' value are equal (unordered).
// Play: todo
func EqualUnordered[T comparable](slice1, slice2 []T) bool {
if len(slice1) != len(slice2) {
return false
}
seen := make(map[T]int)
for _, v := range slice1 {
seen[v]++
}
for _, v := range slice2 {
if seen[v] == 0 {
return false
}
seen[v]--
}
return true
}
// Every return true if all of the values in the slice pass the predicate function.
// Play: https://go.dev/play/p/R8U6Sl-j8cD
func Every[T any](slice []T, predicate func(index int, item T) bool) bool {

View File

@@ -1300,3 +1300,15 @@ func ExampleConcatBy() {
// Alice | Bob | Charlie
// 90
}
func ExampleEqualUnordered() {
result1 := EqualUnordered([]int{1, 2, 3}, []int{3, 2, 1})
result2 := EqualUnordered([]int{1, 2, 3}, []int{4, 5, 6})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}

View File

@@ -1926,3 +1926,25 @@ func TestConcatBy(t *testing.T) {
assert.Equal(90, result.Age)
})
}
func TestEqualUnordered(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestEqualUnordered")
tests := []struct {
slice1, slice2 []int
expected bool
}{
{[]int{}, []int{}, true},
{[]int{1, 2, 3}, []int{1, 2, 3}, true},
{[]int{1, 2, 3}, []int{3, 2, 1}, true},
{[]int{1, 2, 3}, []int{1, 2, 3, 4}, false},
{[]int{1, 2, 3}, []int{1, 2}, false},
{[]int{1, 2, 3}, []int{1, 2, 4}, false},
}
for _, test := range tests {
assert.Equal(test.expected, EqualUnordered(test.slice1, test.slice2))
}
}