Skip to content

Commit

Permalink
feat: add FilterConcurrent
Browse files Browse the repository at this point in the history
  • Loading branch information
duke-git committed Aug 14, 2024
1 parent 7f78a6b commit a360372
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 1 deletion.
35 changes: 35 additions & 0 deletions docs/api/packages/slice.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import (
- [Equal](#Equal)
- [EqualWith](#EqualWith)
- [Filter](#Filter)
- [FilterConcurrent](#FilterConcurrent)
- [Find<sup>deprecated</sup>](#Find)
- [FindBy](#FindBy)
- [FindLast<sup>deprecated</sup>](#FindLast)
Expand Down Expand Up @@ -901,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>
Expand Down
35 changes: 35 additions & 0 deletions docs/en/api/packages/slice.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import (
- [EqualWith](#EqualWith)
- [Every](#Every)
- [Filter](#Filter)
- [FilterConcurrent](#FilterConcurrent)
- [Find<sup>deprecated</sup>](#Find)
- [FindBy](#FindBy)
- [FindLast<sup>deprecated</sup>](#FindLast)
Expand Down Expand Up @@ -899,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>
Expand Down
31 changes: 30 additions & 1 deletion slice/slice_concurrent.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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
Expand Down
15 changes: 15 additions & 0 deletions slice/slice_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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}

Expand Down
26 changes: 26 additions & 0 deletions slice/slice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})

}

0 comments on commit a360372

Please sign in to comment.