1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-15 02:02:27 +08:00

feat: add MapConcurrent

This commit is contained in:
dudaodong
2024-08-14 10:45:35 +08:00
parent f7e9d5dc47
commit 5c53cb5867
5 changed files with 130 additions and 1 deletions

View File

@@ -1451,7 +1451,7 @@ func main() {
### <span id="Map">Map</span> ### <span id="Map">Map</span>
<p>对slice中的每个元素执行map函数以创建一个新切片</p> <p>对slice中的每个元素执行map函数以创建一个新切片</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -1483,6 +1483,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> ### <span id="FilterMap">FilterMap</span>
<p>返回一个将filter和map操作应用于给定切片的切片。 iteratee回调函数应该返回两个值1结果值。2结果值是否应该被包含在返回的切片中。</p> <p>返回一个将filter和map操作应用于给定切片的切片。 iteratee回调函数应该返回两个值1结果值。2结果值是否应该被包含在返回的切片中。</p>

View File

@@ -61,6 +61,7 @@ import (
- [IndexOf](#IndexOf) - [IndexOf](#IndexOf)
- [LastIndexOf](#LastIndexOf) - [LastIndexOf](#LastIndexOf)
- [Map](#Map) - [Map](#Map)
- [MapConcurrent](#MapConcurrent)
- [FilterMap](#FilterMap) - [FilterMap](#FilterMap)
- [FlatMap](#FlatMap) - [FlatMap](#FlatMap)
- [Merge](#Merge) - [Merge](#Merge)
@@ -1481,6 +1482,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> ### <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> <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>

View File

@@ -1139,6 +1139,7 @@ func ExampleRandom() {
if idx >= 0 && idx < len(nums) && Contain(nums, val) { if idx >= 0 && idx < len(nums) && Contain(nums, val) {
fmt.Println("okk") fmt.Println("okk")
} }
// Output: // Output:
// okk // okk
} }
@@ -1148,6 +1149,7 @@ func ExampleSetToDefaultIf() {
modifiedStrs, count := SetToDefaultIf(strs, func(s string) bool { return "a" == s }) modifiedStrs, count := SetToDefaultIf(strs, func(s string) bool { return "a" == s })
fmt.Println(modifiedStrs) fmt.Println(modifiedStrs)
fmt.Println(count) fmt.Println(count)
// Output: // Output:
// [ b c d ] // [ b c d ]
// 3 // 3
@@ -1170,6 +1172,7 @@ func ExampleRightPadding() {
nums := []int{1, 2, 3, 4, 5} nums := []int{1, 2, 3, 4, 5}
padded := RightPadding(nums, 0, 3) padded := RightPadding(nums, 0, 3)
fmt.Println(padded) fmt.Println(padded)
// Output: // Output:
// [1 2 3 4 5 0 0 0] // [1 2 3 4 5 0 0 0]
} }
@@ -1178,6 +1181,7 @@ func ExampleLeftPadding() {
nums := []int{1, 2, 3, 4, 5} nums := []int{1, 2, 3, 4, 5}
padded := LeftPadding(nums, 0, 3) padded := LeftPadding(nums, 0, 3)
fmt.Println(padded) fmt.Println(padded)
// Output: // Output:
// [0 0 0 1 2 3 4 5] // [0 0 0 1 2 3 4 5]
} }
@@ -1190,6 +1194,17 @@ func ExampleUniqueByParallel() {
result := UniqueByParallel(nums, numOfThreads, comparator) result := UniqueByParallel(nums, numOfThreads, comparator)
fmt.Println(result) fmt.Println(result)
// Output: // Output:
// [1 2 3 4 5 6 7] // [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

@@ -8,6 +8,33 @@ import (
"sync" "sync"
) )
// MapConcurrent applies the iteratee function to each item in the slice by concrrent.
// 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
}
// UniqueByParallel removes duplicate elements from the slice by parallel // UniqueByParallel removes duplicate elements from the slice by parallel
// The comparator function is used to compare the elements // The comparator function is used to compare the elements
// The numOfThreads parameter specifies the number of threads to use // The numOfThreads parameter specifies the number of threads to use

View File

@@ -1516,3 +1516,29 @@ func TestUniqueByParallel(t *testing.T) {
assert.Equal([]int{1, 2, 3, 4, 5, 6, 7}, result) 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)
})
}