mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-04 12:52:28 +08:00
feat: add ReduceConcurrent
This commit is contained in:
@@ -70,6 +70,7 @@ import (
|
|||||||
- [Merge](#Merge)
|
- [Merge](#Merge)
|
||||||
- [Reverse](#Reverse)
|
- [Reverse](#Reverse)
|
||||||
- [Reduce<sup>deprecated</sup>](#Reduce)
|
- [Reduce<sup>deprecated</sup>](#Reduce)
|
||||||
|
- [ReduceConcurrent](#ReduceConcurrent)
|
||||||
- [ReduceBy](#ReduceBy)
|
- [ReduceBy](#ReduceBy)
|
||||||
- [ReduceRight](#ReduceRight)
|
- [ReduceRight](#ReduceRight)
|
||||||
- [Replace](#Replace)
|
- [Replace](#Replace)
|
||||||
@@ -1578,15 +1579,15 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
nums := []int{1, 2, 3, 4, 5, 6}
|
nums := []int{1, 2, 3, 4, 5, 6}
|
||||||
|
|
||||||
result := slice.MapConcurrent(nums, func(_, n int) int {
|
result := slice.MapConcurrent(nums, func(_, n int) int {
|
||||||
return n * n
|
return n * n
|
||||||
}, 4)
|
}, 4)
|
||||||
|
|
||||||
fmt.Println(result)
|
fmt.Println(result)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// [1 4 9 16 25 36]
|
// [1 4 9 16 25 36]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -1759,6 +1760,38 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="ReduceConcurrent">ReduceConcurrent</span>
|
||||||
|
|
||||||
|
<p>对切片元素执行并发reduce操作。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ReduceConcurrent[T any](slice []T, initial T, reducer func(index int, item T, agg T) T, numThreads int) T
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||||
|
|
||||||
|
result := slice.ReduceConcurrent(nums, 0, func(_ int, item, agg int) int {
|
||||||
|
return agg + item
|
||||||
|
}, 1)
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 55
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### <span id="ReduceBy">ReduceBy</span>
|
### <span id="ReduceBy">ReduceBy</span>
|
||||||
|
|
||||||
<p>对切片元素执行reduce操作。</p>
|
<p>对切片元素执行reduce操作。</p>
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ import (
|
|||||||
- [Merge](#Merge)
|
- [Merge](#Merge)
|
||||||
- [Reverse](#Reverse)
|
- [Reverse](#Reverse)
|
||||||
- [Reduce<sup>deprecated</sup>](#Reduce)
|
- [Reduce<sup>deprecated</sup>](#Reduce)
|
||||||
|
- [ReduceConcurrent](#ReduceConcurrent)
|
||||||
- [ReduceBy](#ReduceBy)
|
- [ReduceBy](#ReduceBy)
|
||||||
- [ReduceRight](#ReduceRight)
|
- [ReduceRight](#ReduceRight)
|
||||||
- [Replace](#Replace)
|
- [Replace](#Replace)
|
||||||
@@ -1754,6 +1755,39 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="ReduceConcurrent">ReduceConcurrent</span>
|
||||||
|
|
||||||
|
<p>Reduces the slice to a single value by applying the reducer function to each item in the slice concurrently.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func ReduceConcurrent[T any](slice []T, initial T, reducer func(index int, item T, agg T) T, numThreads int) T
|
||||||
|
```
|
||||||
|
|
||||||
|
<b>Example:<span style="float:right;display:inline-block;">[运行]()</span></b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||||
|
|
||||||
|
result := slice.ReduceConcurrent(nums, 0, func(_ int, item, agg int) int {
|
||||||
|
return agg + item
|
||||||
|
}, 1)
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 55
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="ReduceBy">ReduceBy</span>
|
### <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>
|
<p>Produces a value from slice by accumulating the result of each element as passed through the reducer function.</p>
|
||||||
|
|||||||
@@ -76,6 +76,50 @@ func MapConcurrent[T any, U any](slice []T, iteratee func(index int, item T) U,
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReduceConcurrent reduces the slice to a single value by applying the reducer function to each item in the slice concurrently.
|
||||||
|
// Play: todo
|
||||||
|
func ReduceConcurrent[T any](slice []T, initial T, reducer func(index int, item T, agg T) T, numThreads int) T {
|
||||||
|
if numThreads <= 0 {
|
||||||
|
numThreads = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
var mu sync.Mutex
|
||||||
|
|
||||||
|
sliceLen := len(slice)
|
||||||
|
chunkSize := (sliceLen + numThreads - 1) / numThreads
|
||||||
|
results := make([]T, numThreads)
|
||||||
|
|
||||||
|
for i := 0; i < numThreads; i++ {
|
||||||
|
start := i * chunkSize
|
||||||
|
end := start + chunkSize
|
||||||
|
if end > sliceLen {
|
||||||
|
end = sliceLen
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go func(i, start, end int) {
|
||||||
|
defer wg.Done()
|
||||||
|
tempResult := initial
|
||||||
|
for j := start; j < end; j++ {
|
||||||
|
tempResult = reducer(j, slice[j], tempResult)
|
||||||
|
}
|
||||||
|
mu.Lock()
|
||||||
|
results[i] = tempResult
|
||||||
|
mu.Unlock()
|
||||||
|
}(i, start, end)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
result := initial
|
||||||
|
for i, r := range results {
|
||||||
|
result = reducer(i, result, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// FilterConcurrent applies the provided filter function `predicate` to each element of the input slice concurrently.
|
// FilterConcurrent applies the provided filter function `predicate` to each element of the input slice concurrently.
|
||||||
// Play: todo
|
// Play: todo
|
||||||
func FilterConcurrent[T any](slice []T, predicate func(index int, item T) bool, numThreads int) []T {
|
func FilterConcurrent[T any](slice []T, predicate func(index int, item T) bool, numThreads int) []T {
|
||||||
|
|||||||
@@ -527,6 +527,18 @@ func ExampleReduce() {
|
|||||||
// 6
|
// 6
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleReduceConcurrent() {
|
||||||
|
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||||
|
result := ReduceConcurrent(nums, 0, func(_ int, item, agg int) int {
|
||||||
|
return agg + item
|
||||||
|
}, 1)
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 55
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleReduceBy() {
|
func ExampleReduceBy() {
|
||||||
result1 := ReduceBy([]int{1, 2, 3, 4}, 0, func(_ int, item int, agg int) int {
|
result1 := ReduceBy([]int{1, 2, 3, 4}, 0, func(_ int, item int, agg int) int {
|
||||||
return agg + item
|
return agg + item
|
||||||
|
|||||||
@@ -587,6 +587,44 @@ func TestReduce(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReduceConcurrent(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestReduceConcurrent")
|
||||||
|
|
||||||
|
t.Run("basic", func(t *testing.T) {
|
||||||
|
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||||
|
result := ReduceConcurrent(nums, 0, func(_ int, item, agg int) int {
|
||||||
|
return agg + item
|
||||||
|
}, 4)
|
||||||
|
assert.Equal(55, result)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("empty slice", func(t *testing.T) {
|
||||||
|
nums := []int{}
|
||||||
|
result := ReduceConcurrent(nums, 0, func(_ int, item, agg int) int {
|
||||||
|
return agg + item
|
||||||
|
}, 4)
|
||||||
|
assert.Equal(0, result)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("single thread", func(t *testing.T) {
|
||||||
|
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||||
|
result := ReduceConcurrent(nums, 0, func(_ int, item, agg int) int {
|
||||||
|
return agg + item
|
||||||
|
}, 1)
|
||||||
|
assert.Equal(55, result)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("negative threads", func(t *testing.T) {
|
||||||
|
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||||
|
result := ReduceConcurrent(nums, 0, func(_ int, item, agg int) int {
|
||||||
|
return agg + item
|
||||||
|
}, -1)
|
||||||
|
assert.Equal(55, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestReduceBy(t *testing.T) {
|
func TestReduceBy(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user