diff --git a/docs/api/packages/slice.md b/docs/api/packages/slice.md index 5130f370..1cf2a5b8 100644 --- a/docs/api/packages/slice.md +++ b/docs/api/packages/slice.md @@ -45,6 +45,7 @@ import ( - [Equal](#Equal) - [EqualWith](#EqualWith) - [Filter](#Filter) +- [FilterConcurrent](#FilterConcurrent) - [Finddeprecated](#Find) - [FindBy](#FindBy) - [FindLastdeprecated](#FindLast) @@ -901,6 +902,40 @@ func main() { } ``` +### FilterConcurrent + +
对slice并发执行filter操作。
+ +函数签名: + +```go +func FilterConcurrent[T any](slice []T, numOfThreads int, predicate func(index int, item T) bool) []T +``` + +示例: + +```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] +} +``` + ### Find遍历slice的元素,返回第一个通过predicate函数真值测试的元素
diff --git a/docs/en/api/packages/slice.md b/docs/en/api/packages/slice.md index 6a57bc06..fbbbaf9f 100644 --- a/docs/en/api/packages/slice.md +++ b/docs/en/api/packages/slice.md @@ -45,6 +45,7 @@ import ( - [EqualWith](#EqualWith) - [Every](#Every) - [Filter](#Filter) +- [FilterConcurrent](#FilterConcurrent) - [Finddeprecated](#Find) - [FindBy](#FindBy) - [FindLastdeprecated](#FindLast) @@ -899,6 +900,40 @@ func main() { } ``` +### FilterConcurrent + +Applies the provided filter function `predicate` to each element of the input slice concurrently.
+ +Signature: + +```go +func FilterConcurrent[T any](slice []T, numOfThreads int, predicate func(index int, item T) bool) []T +``` + +Example: + +```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] +} +``` + ### FindIterates over elements of slice, returning the first one that passes a truth test on function.
diff --git a/slice/slice_concurrent.go b/slice/slice_concurrent.go index 18767778..1f0ada97 100644 --- a/slice/slice_concurrent.go +++ b/slice/slice_concurrent.go @@ -8,7 +8,7 @@ import ( "sync" ) -// MapConcurrent applies the iteratee function to each item in the slice by concrrent. +// 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)) @@ -35,6 +35,35 @@ func MapConcurrent[T any, U any](slice []T, numOfThreads int, iteratee func(inde 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 diff --git a/slice/slice_example_test.go b/slice/slice_example_test.go index 2a709b9a..9d9de3d4 100644 --- a/slice/slice_example_test.go +++ b/slice/slice_example_test.go @@ -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} diff --git a/slice/slice_test.go b/slice/slice_test.go index 1530b602..8a83df64 100644 --- a/slice/slice_test.go +++ b/slice/slice_test.go @@ -1542,3 +1542,29 @@ func TestMapConcurrent(t *testing.T) { }) } + +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) + }) + +}