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

Compare commits

...

3 Commits

Author SHA1 Message Date
dudaodong
a360372aa9 feat: add FilterConcurrent 2024-08-14 11:19:10 +08:00
dudaodong
7f78a6b11e refactoring: rename slice_parallel to slice_concurrent 2024-08-14 10:52:36 +08:00
dudaodong
5c53cb5867 feat: add MapConcurrent 2024-08-14 10:45:35 +08:00
5 changed files with 289 additions and 17 deletions

View File

@@ -6,7 +6,8 @@ slice 包包含操作切片的方法集合。
## 源码:
- [https://github.com/duke-git/lancet/blob/main/slice/slice.go](https://github.com/duke-git/lancet/blob/main/slice/slice.go)
- [https://github.com/duke-git/lancet/blob/main/slice/slice.go](https://github.com/duke-git/lancet/blob/main/slice/slice.go)
- [https://github.com/duke-git/lancet/blob/main/slice/slice_concurrent.go](https://github.com/duke-git/lancet/blob/main/slice/slice_concurrent.go)
<div STYLE="page-break-after: always;"></div>
@@ -44,6 +45,7 @@ import (
- [Equal](#Equal)
- [EqualWith](#EqualWith)
- [Filter](#Filter)
- [FilterConcurrent](#FilterConcurrent)
- [Find<sup>deprecated</sup>](#Find)
- [FindBy](#FindBy)
- [FindLast<sup>deprecated</sup>](#FindLast)
@@ -61,6 +63,7 @@ import (
- [IndexOf](#IndexOf)
- [LastIndexOf](#LastIndexOf)
- [Map](#Map)
- [MapConcurrent](#MapConcurrent)
- [FilterMap](#FilterMap)
- [FlatMap](#FlatMap)
- [Merge](#Merge)
@@ -88,7 +91,7 @@ import (
- [UniqueBy](#UniqueBy)
- [UniqueByComparator](#UniqueByComparator)
- [UniqueByField](#UniqueByField)
- [UniqueByParallel](#UniqueByParallel)
- [UniqueByConcurrent](#UniqueByConcurrent)
- [Union](#Union)
- [UnionBy](#UnionBy)
- [UpdateAt](#UpdateAt)
@@ -899,6 +902,40 @@ func main() {
}
```
### <span id="FilterConcurrent">FilterConcurrent</span>
<p>对slice并发执行filter操作。</p>
<b>函数签名:</b>
```go
func FilterConcurrent[T any](slice []T, numOfThreads int, predicate func(index int, item T) bool) []T
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
result := slice.FilterConcurrent(nums, 2, isEven)
fmt.Println(result)
// Output:
// [2 4]
}
```
### <span id="Find">Find</span>
<p>遍历slice的元素返回第一个通过predicate函数真值测试的元素</p>
@@ -1451,7 +1488,7 @@ func main() {
### <span id="Map">Map</span>
<p>对slice中的每个元素执行map函数以创建一个新切片</p>
<p>对slice中的每个元素执行map函数以创建一个新切片</p>
<b>函数签名:</b>
@@ -1483,6 +1520,36 @@ func main() {
}
```
### <span id="MapConcurrent">MapConcurrent</span>
<p>对slice并发执行map操作。</p>
<b>函数签名:</b>
```go
func MapConcurrent[T any, U any](slice []T, numOfThreads int, iteratee func(index int, item T) U) []U
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5, 6}
result := slice.MapConcurrent(nums, 4, func(_, n int) int { return n * n })
fmt.Println(result)
// Output:
// [1 4 9 16 25 36]
}
```
### <span id="FilterMap">FilterMap</span>
<p>返回一个将filter和map操作应用于给定切片的切片。 iteratee回调函数应该返回两个值1结果值。2结果值是否应该被包含在返回的切片中。</p>
@@ -2365,14 +2432,14 @@ func main() {
}
```
### <span id="UniqueByParallel">UniqueByParallel</span>
### <span id="UniqueByConcurrent">UniqueByConcurrent</span>
<p>并发的从输入切片中移除重复元素,结果保持元素的顺序。</p>
<b>函数签名:</b>
```go
func UniqueByParallel[T comparable](slice []T, numOfThreads int, comparator func(item T, other T) bool) []T
func UniqueByConcurrent[T comparable](slice []T, numOfThreads int, comparator func(item T, other T) bool) []T
```
<b>示例:</b>
@@ -2388,7 +2455,7 @@ func main() {
numOfThreads := 4
comparator := func(item int, other int) bool { return item == other }
result := slice.UniqueByParallel(nums, numOfThreads, comparator)
result := slice.UniqueByConcurrent(nums, numOfThreads, comparator)
fmt.Println(result)
// Output:

View File

@@ -6,7 +6,8 @@ Package slice implements some functions to manipulate slice.
## Source:
- [https://github.com/duke-git/lancet/blob/main/slice/slice.go](https://github.com/duke-git/lancet/blob/main/slice/slice.go)
- [https://github.com/duke-git/lancet/blob/main/slice/slice.go](https://github.com/duke-git/lancet/blob/main/slice/slice.go)
- [https://github.com/duke-git/lancet/blob/main/slice/slice_concurrent.go](https://github.com/duke-git/lancet/blob/main/slice/slice_concurrent.go)
<div STYLE="page-break-after: always;"></div>
@@ -44,6 +45,7 @@ import (
- [EqualWith](#EqualWith)
- [Every](#Every)
- [Filter](#Filter)
- [FilterConcurrent](#FilterConcurrent)
- [Find<sup>deprecated</sup>](#Find)
- [FindBy](#FindBy)
- [FindLast<sup>deprecated</sup>](#FindLast)
@@ -61,6 +63,7 @@ import (
- [IndexOf](#IndexOf)
- [LastIndexOf](#LastIndexOf)
- [Map](#Map)
- [MapConcurrent](#MapConcurrent)
- [FilterMap](#FilterMap)
- [FlatMap](#FlatMap)
- [Merge](#Merge)
@@ -88,7 +91,7 @@ import (
- [UniqueBy](#UniqueBy)
- [UniqueByComparator](#UniqueByComparator)
- [UniqueByField](#UniqueByField)
- [UniqueByParallel](#UniqueByParallel)
- [UniqueByConcurrent](#UniqueByConcurrent)
- [Union](#Union)
- [UnionBy](#UnionBy)
- [UpdateAt](#UpdateAt)
@@ -897,6 +900,40 @@ func main() {
}
```
### <span id="FilterConcurrent">FilterConcurrent</span>
<p>Applies the provided filter function `predicate` to each element of the input slice concurrently.</p>
<b>Signature:</b>
```go
func FilterConcurrent[T any](slice []T, numOfThreads int, predicate func(index int, item T) bool) []T
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
result := slice.FilterConcurrent(nums, 2, isEven)
fmt.Println(result)
// Output:
// [2 4]
}
```
### <span id="Find">Find</span>
<p>Iterates over elements of slice, returning the first one that passes a truth test on function.</p>
@@ -1481,6 +1518,36 @@ func main() {
}
```
### <span id="MapConcurrent">MapConcurrent</span>
<p>Applies the iteratee function to each item in the slice by concrrent.</p>
<b>Signature:</b>
```go
func MapConcurrent[T any, U any](slice []T, numOfThreads int, iteratee func(index int, item T) U) []U
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5, 6}
result := slice.MapConcurrent(nums, 4, func(_, n int) int { return n * n })
fmt.Println(result)
// Output:
// [1 4 9 16 25 36]
}
```
### <span id="FilterMap">FilterMap</span>
<p>Returns a slice which apply both filtering and mapping to the given slice. iteratee callback function should returntwo values: 1, mapping result. 2, whether the result element should be included or not.</p>
@@ -2363,14 +2430,14 @@ func main() {
}
```
### <span id="UniqueByParallel">UniqueByParallel</span>
### <span id="UniqueByConcurrent">UniqueByConcurrent</span>
<p>Removes duplicate elements from the slice by parallel.</p>
<b>Signature:</b>
```go
func UniqueByParallel[T comparable](slice []T, numOfThreads int, comparator func(item T, other T) bool) []T
func UniqueByConcurrent[T comparable](slice []T, numOfThreads int, comparator func(item T, other T) bool) []T
```
<b>Example:</b>
@@ -2386,7 +2453,7 @@ func main() {
numOfThreads := 4
comparator := func(item int, other int) bool { return item == other }
result := slice.UniqueByParallel(nums, numOfThreads, comparator)
result := slice.UniqueByConcurrent(nums, numOfThreads, comparator)
fmt.Println(result)
// Output:

View File

@@ -8,13 +8,69 @@ import (
"sync"
)
// MapConcurrent applies the iteratee function to each item in the slice concurrently.
// Play: todo
func MapConcurrent[T any, U any](slice []T, numOfThreads int, iteratee func(index int, item T) U) []U {
result := make([]U, len(slice))
var wg sync.WaitGroup
workerChan := make(chan struct{}, numOfThreads)
for index, item := range slice {
wg.Add(1)
workerChan <- struct{}{}
go func(i int, v T) {
defer wg.Done()
result[i] = iteratee(i, v)
<-workerChan
}(index, item)
}
wg.Wait()
return result
}
// FilterConcurrent applies the provided filter function `predicate` to each element of the input slice concurrently.
// Play: todo
func FilterConcurrent[T any](slice []T, numOfThreads int, predicate func(index int, item T) bool) []T {
result := make([]T, 0)
var wg sync.WaitGroup
workerChan := make(chan struct{}, numOfThreads)
for index, item := range slice {
wg.Add(1)
workerChan <- struct{}{}
go func(i int, v T) {
defer wg.Done()
if predicate(i, v) {
result = append(result, v)
}
<-workerChan
}(index, item)
}
wg.Wait()
return result
}
// UniqueByParallel removes duplicate elements from the slice by parallel
// The comparator function is used to compare the elements
// The numOfThreads parameter specifies the number of threads to use
// If numOfThreads is less than or equal to 0, it will be set to 1
// The comparator function should return true if the two elements are equal
// Play: todo
func UniqueByParallel[T comparable](slice []T, numOfThreads int, comparator func(item T, other T) bool) []T {
func UniqueByConcurrent[T comparable](slice []T, numOfThreads int, comparator func(item T, other T) bool) []T {
if numOfThreads <= 0 {
numOfThreads = 1
} else if numOfThreads > len(slice) {

View File

@@ -247,6 +247,21 @@ func ExampleFilter() {
// [2 4]
}
func ExampleFilterConcurrent() {
nums := []int{1, 2, 3, 4, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
result := FilterConcurrent(nums, 2, isEven)
fmt.Println(result)
// Output:
// [2 4]
}
func ExampleCount() {
nums := []int{1, 2, 3, 3, 4}
@@ -1139,6 +1154,7 @@ func ExampleRandom() {
if idx >= 0 && idx < len(nums) && Contain(nums, val) {
fmt.Println("okk")
}
// Output:
// okk
}
@@ -1148,6 +1164,7 @@ func ExampleSetToDefaultIf() {
modifiedStrs, count := SetToDefaultIf(strs, func(s string) bool { return "a" == s })
fmt.Println(modifiedStrs)
fmt.Println(count)
// Output:
// [ b c d ]
// 3
@@ -1170,6 +1187,7 @@ func ExampleRightPadding() {
nums := []int{1, 2, 3, 4, 5}
padded := RightPadding(nums, 0, 3)
fmt.Println(padded)
// Output:
// [1 2 3 4 5 0 0 0]
}
@@ -1178,18 +1196,30 @@ func ExampleLeftPadding() {
nums := []int{1, 2, 3, 4, 5}
padded := LeftPadding(nums, 0, 3)
fmt.Println(padded)
// Output:
// [0 0 0 1 2 3 4 5]
}
func ExampleUniqueByParallel() {
func ExampleUniqueByConcurrent() {
nums := []int{1, 2, 3, 1, 2, 4, 5, 6, 4, 7}
numOfThreads := 4
comparator := func(item int, other int) bool { return item == other }
result := UniqueByParallel(nums, numOfThreads, comparator)
result := UniqueByConcurrent(nums, numOfThreads, comparator)
fmt.Println(result)
// Output:
// [1 2 3 4 5 6 7]
}
func ExampleMapConcurrent() {
nums := []int{1, 2, 3, 4, 5, 6}
result := MapConcurrent(nums, 4, func(_, n int) int { return n * n })
fmt.Println(result)
// Output:
// [1 4 9 16 25 36]
}

View File

@@ -1503,16 +1503,68 @@ func TestRightPaddingAndLeftPadding(t *testing.T) {
assert.Equal([]int{0, 0, 0, 1, 2, 3, 4, 5, 0, 0, 0}, padded)
}
func TestUniqueByParallel(t *testing.T) {
func TestUniqueByConcurrent(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestUniqueByParallel")
assert := internal.NewAssert(t, "TestUniqueByConcurrent")
nums := []int{1, 2, 3, 1, 2, 4, 5, 6, 4, 7}
numOfThreads := 4
comparator := func(item int, other int) bool { return item == other }
result := UniqueByParallel(nums, numOfThreads, comparator)
result := UniqueByConcurrent(nums, numOfThreads, comparator)
assert.Equal([]int{1, 2, 3, 4, 5, 6, 7}, result)
}
func TestMapConcurrent(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestMapConcurrent")
t.Run("empty slice", func(t *testing.T) {
actual := MapConcurrent([]int{}, 4, func(_, n int) int { return n * n })
assert.Equal([]int{}, actual)
})
t.Run("single thread", func(t *testing.T) {
nums := []int{1, 2, 3, 4, 5, 6}
expected := []int{1, 4, 9, 16, 25, 36}
actual := MapConcurrent(nums, 1, func(_, n int) int { return n * n })
assert.Equal(expected, actual)
})
t.Run("multiple threads", func(t *testing.T) {
nums := []int{1, 2, 3, 4, 5, 6}
expected := []int{1, 4, 9, 16, 25, 36}
actual := MapConcurrent(nums, 4, func(_, n int) int { return n * n })
assert.Equal(expected, actual)
})
}
func TestFilterConcurrent(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestFilterConcurrent")
t.Run("empty slice", func(t *testing.T) {
actual := FilterConcurrent([]int{}, 4, func(_, n int) bool { return n != 0 })
assert.Equal([]int{}, actual)
})
t.Run("single thread", func(t *testing.T) {
nums := []int{1, 2, 3, 4, 5, 6}
expected := []int{4, 5, 6}
actual := FilterConcurrent(nums, 1, func(_, n int) bool { return n > 3 })
assert.Equal(expected, actual)
})
t.Run("multiple threads", func(t *testing.T) {
nums := []int{1, 2, 3, 4, 5, 6}
expected := []int{4, 5, 6}
actual := FilterConcurrent(nums, 4, func(_, n int) bool { return n > 3 })
assert.Equal(expected, actual)
})
}