diff --git a/docs/api/packages/slice.md b/docs/api/packages/slice.md index 3e618ea..1eaa31e 100644 --- a/docs/api/packages/slice.md +++ b/docs/api/packages/slice.md @@ -1451,7 +1451,7 @@ func main() { ### Map -
对slice中的每个元素执行map函数以创建一个新切片
+对slice中的每个元素执行map函数以创建一个新切片。
函数签名: @@ -1483,6 +1483,36 @@ func main() { } ``` +### MapConcurrent + +对slice并发执行map操作。
+ +函数签名: + +```go +func MapConcurrent[T any, U any](slice []T, numOfThreads int, iteratee func(index int, item T) U) []U +``` + +示例: + +```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] +} +``` + ### FilterMap返回一个将filter和map操作应用于给定切片的切片。 iteratee回调函数应该返回两个值:1,结果值。2,结果值是否应该被包含在返回的切片中。
diff --git a/docs/en/api/packages/slice.md b/docs/en/api/packages/slice.md index 2f9722f..2ee2ab1 100644 --- a/docs/en/api/packages/slice.md +++ b/docs/en/api/packages/slice.md @@ -61,6 +61,7 @@ import ( - [IndexOf](#IndexOf) - [LastIndexOf](#LastIndexOf) - [Map](#Map) +- [MapConcurrent](#MapConcurrent) - [FilterMap](#FilterMap) - [FlatMap](#FlatMap) - [Merge](#Merge) @@ -1481,6 +1482,36 @@ func main() { } ``` +### MapConcurrent + +Applies the iteratee function to each item in the slice by concrrent.
+ +Signature: + +```go +func MapConcurrent[T any, U any](slice []T, numOfThreads int, iteratee func(index int, item T) U) []U +``` + +Example: + +```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] +} +``` + ### FilterMapReturns 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.
diff --git a/slice/slice_example_test.go b/slice/slice_example_test.go index 99ac6cf..68d3982 100644 --- a/slice/slice_example_test.go +++ b/slice/slice_example_test.go @@ -1139,6 +1139,7 @@ func ExampleRandom() { if idx >= 0 && idx < len(nums) && Contain(nums, val) { fmt.Println("okk") } + // Output: // okk } @@ -1148,6 +1149,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 +1172,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,6 +1181,7 @@ 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] } @@ -1190,6 +1194,17 @@ func ExampleUniqueByParallel() { result := UniqueByParallel(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] +} diff --git a/slice/slice_parallel.go b/slice/slice_parallel.go index d485d8c..838c6d2 100644 --- a/slice/slice_parallel.go +++ b/slice/slice_parallel.go @@ -8,6 +8,33 @@ import ( "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 // The comparator function is used to compare the elements // The numOfThreads parameter specifies the number of threads to use diff --git a/slice/slice_test.go b/slice/slice_test.go index 85b9049..da8d831 100644 --- a/slice/slice_test.go +++ b/slice/slice_test.go @@ -1516,3 +1516,29 @@ func TestUniqueByParallel(t *testing.T) { 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) + }) + +}