1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-23 13:52:26 +08:00

Compare commits

...

4 Commits

Author SHA1 Message Date
dudaodong
c0b200f846 feat: add ReduceConcurrent 2024-08-15 17:48:26 +08:00
dudaodong
305847993c feat: add ForEachConcurrent 2024-08-15 16:44:22 +08:00
dudaodong
f5d70728c3 refactoring: rename param and change its order 2024-08-15 15:50:48 +08:00
残念
c2a5335bc6 feat: add RandSliceFromGivenSlice function (#236) 2024-08-15 15:20:36 +08:00
10 changed files with 539 additions and 56 deletions

View File

@@ -26,6 +26,7 @@ import (
- [RandInt](#RandInt)
- [RandString](#RandString)
- [RandFromGivenSlice](#RandFromGivenSlice)
- [RandSliceFromGivenSlice](#RandSliceFromGivenSlice)
- [RandUpper](#RandUpper)
- [RandLower](#RandLower)
- [RandNumeral](#RandNumeral)
@@ -150,6 +151,33 @@ func main() {
}
```
### <span id="RandSliceFromGivenSlice">RandSliceFromGivenSlice</span>
<p>从给定切片中生成长度为 num 的随机切片</p>
<b>函数签名:</b>
```go
func RandSliceFromGivenSlice[T any](slice []T, num int, repeatable bool) []T
```
<b>示例:<span style="float:right;display:inline-block;">[运行]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
goods := []string{"apple", "banana", "cherry", "elderberry", "fig", "grape", "honeydew", "kiwi", "lemon","mango", "nectarine", "orange"}
chosen3goods := random.RandSliceFromGivenSlice(goods, 3, false)
fmt.Println(chosen3goods)
}
```
### <span id="RandUpper">RandUpper</span>
<p>生成给定长度的随机大写字母字符串</p>

View File

@@ -53,6 +53,7 @@ import (
- [Flatten](#Flatten)
- [FlattenDeep](#FlattenDeep)
- [ForEach](#ForEach)
- [ForEachConcurrent](#ForEachConcurrent)
- [ForEachWithBreak](#ForEachWithBreak)
- [GroupBy](#GroupBy)
- [GroupWith](#GroupWith)
@@ -69,6 +70,7 @@ import (
- [Merge](#Merge)
- [Reverse](#Reverse)
- [Reduce<sup>deprecated</sup>](#Reduce)
- [ReduceConcurrent](#ReduceConcurrent)
- [ReduceBy](#ReduceBy)
- [ReduceRight](#ReduceRight)
- [Replace](#Replace)
@@ -909,7 +911,7 @@ func main() {
<b>函数签名:</b>
```go
func FilterConcurrent[T any](slice []T, numOfThreads int, predicate func(index int, item T) bool) []T
func FilterConcurrent[T any](slice []T, predicate func(index int, item T) bool, numThreads int) []T
```
<b>示例:</b>
@@ -927,7 +929,7 @@ func main() {
return num%2 == 0
}
result := slice.FilterConcurrent(nums, 2, isEven)
result := slice.FilterConcurrent(nums, isEven, 2)
fmt.Println(result)
@@ -1179,6 +1181,43 @@ func main() {
}
```
### <span id="ForEachConcurrent">ForEachConcurrent</span>
<p>对slice并发执行foreach操作。</p>
<b>函数签名:</b>
```go
func ForEachConcurrent[T any](slice []T, iteratee func(index int, item T), numThreads int)
```
<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}
result := make([]int, len(nums))
addOne := func(index int, value int) {
result[index] = value + 1
}
slice.ForEachConcurrent(nums, addOne, 4)
fmt.Println(result)
// Output:
// [2 3 4 5 6 7 8 9]
}
```
### <span id="ForEachWithBreak">ForEachWithBreak</span>
<p>遍历切片的元素并为每个元素调用iteratee函数当iteratee函数返回false时终止遍历。</p>
@@ -1527,7 +1566,7 @@ func main() {
<b>函数签名:</b>
```go
func MapConcurrent[T any, U any](slice []T, numOfThreads int, iteratee func(index int, item T) U) []U
func MapConcurrent[T any, U any](slice []T, iteratee func(index int, item T) U, numThreads int) []U
```
<b>示例:</b>
@@ -1540,13 +1579,15 @@ import (
func main() {
nums := []int{1, 2, 3, 4, 5, 6}
result := slice.MapConcurrent(nums, 4, func(_, n int) int { return n * n })
result := slice.MapConcurrent(nums, func(_, n int) int {
return n * n
}, 4)
fmt.Println(result)
fmt.Println(result)
// Output:
// [1 4 9 16 25 36]
// Output:
// [1 4 9 16 25 36]
}
```
@@ -1719,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>
<p>对切片元素执行reduce操作。</p>
@@ -2439,7 +2512,7 @@ func main() {
<b>函数签名:</b>
```go
func UniqueByConcurrent[T comparable](slice []T, numOfThreads int, comparator func(item T, other T) bool) []T
func UniqueByConcurrent[T comparable](slice []T, comparator func(item T, other T) bool, numThreads int) []T
```
<b>示例:</b>
@@ -2452,10 +2525,9 @@ import (
func main() {
nums := []int{1, 2, 3, 1, 2, 4, 5, 6, 4, 7}
numOfThreads := 4
comparator := func(item int, other int) bool { return item == other }
result := slice.UniqueByConcurrent(nums, numOfThreads, comparator)
result := slice.UniqueByConcurrent(nums, comparator, 4)
fmt.Println(result)
// Output:

View File

@@ -25,6 +25,8 @@ import (
- [RandBytes](#RandBytes)
- [RandInt](#RandInt)
- [RandString](#RandString)
- [RandFromGivenSlice](#RandFromGivenSlice)
- [RandSliceFromGivenSlice](#RandSliceFromGivenSlice)
- [RandUpper](#RandUpper)
- [RandLower](#RandLower)
- [RandNumeral](#RandNumeral)
@@ -148,6 +150,33 @@ func main() {
}
```
### <span id="RandSliceFromGivenSlice">RandSliceFromGivenSlice</span>
<p>Generate a random slice of length num from given slice.</p>
<b>Signature:</b>
```go
func RandSliceFromGivenSlice[T any](slice []T, num int, repeatable bool) []T
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/random"
)
func main() {
goods := []string{"apple", "banana", "cherry", "elderberry", "fig", "grape", "honeydew", "kiwi", "lemon", "mango", "nectarine", "orange"}
chosen3goods := random.RandSliceFromGivenSlice(goods, 3, false)
fmt.Println(chosen3goods)
}
```
### <span id="RandUpper">RandUpper</span>
<p>Generate a random upper case string</p>

View File

@@ -53,6 +53,7 @@ import (
- [Flatten](#Flatten)
- [FlattenDeep](#FlattenDeep)
- [ForEach](#ForEach)
- [ForEachConcurrent](#ForEachConcurrent)
- [ForEachWithBreak](#ForEachWithBreak)
- [GroupBy](#GroupBy)
- [GroupWith](#GroupWith)
@@ -69,6 +70,7 @@ import (
- [Merge](#Merge)
- [Reverse](#Reverse)
- [Reduce<sup>deprecated</sup>](#Reduce)
- [ReduceConcurrent](#ReduceConcurrent)
- [ReduceBy](#ReduceBy)
- [ReduceRight](#ReduceRight)
- [Replace](#Replace)
@@ -907,7 +909,7 @@ func main() {
<b>Signature:</b>
```go
func FilterConcurrent[T any](slice []T, numOfThreads int, predicate func(index int, item T) bool) []T
func FilterConcurrent[T any](slice []T, predicate func(index int, item T) bool, numThreads int) []T
```
<b>Example:</b>
@@ -925,7 +927,7 @@ func main() {
return num%2 == 0
}
result := slice.FilterConcurrent(nums, 2, isEven)
result := slice.FilterConcurrent(nums, isEven, 2)
fmt.Println(result)
@@ -1177,6 +1179,42 @@ func main() {
}
```
### <span id="ForEachConcurrent">ForEachConcurrent</span>
<p>Applies the iteratee function to each item in the slice concurrently.</p>
<b>Signature:</b>
```go
func ForEachConcurrent[T any](slice []T, iteratee func(index int, item T), numThreads int)
```
<b>Example:<span style="float:right;display:inline-block;">[Run]()</span></b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5, 6, 7, 8}
result := make([]int, len(nums))
addOne := func(index int, value int) {
result[index] = value + 1
}
slice.ForEachConcurrent(nums, addOne, 4)
fmt.Println(result)
// Output:
// [2 3 4 5 6 7 8 9]
}
```
### <span id="ForEachWithBreak">ForEachWithBreak</span>
<p>Iterates over elements of slice and invokes function for each element, when iteratee return false, will break the for each loop.</p>
@@ -1525,7 +1563,7 @@ func main() {
<b>Signature:</b>
```go
func MapConcurrent[T any, U any](slice []T, numOfThreads int, iteratee func(index int, item T) U) []U
func MapConcurrent[T any, U any](slice []T, iteratee func(index int, item T) U, numThreads int) []U
```
<b>Example:</b>
@@ -1539,7 +1577,7 @@ import (
func main() {
nums := []int{1, 2, 3, 4, 5, 6}
result := slice.MapConcurrent(nums, 4, func(_, n int) int { return n * n })
result := slice.MapConcurrent(nums, func(_, n int) int { return n * n }, 4)
fmt.Println(result)
@@ -1717,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>
<p>Produces a value from slice by accumulating the result of each element as passed through the reducer function.</p>
@@ -2437,7 +2508,7 @@ func main() {
<b>Signature:</b>
```go
func UniqueByConcurrent[T comparable](slice []T, numOfThreads int, comparator func(item T, other T) bool) []T
func UniqueByConcurrent[T comparable](slice []T, comparator func(item T, other T) bool, numThreads int) []T
```
<b>Example:</b>
@@ -2450,10 +2521,9 @@ import (
func main() {
nums := []int{1, 2, 3, 1, 2, 4, 5, 6, 4, 7}
numOfThreads := 4
comparator := func(item int, other int) bool { return item == other }
result := slice.UniqueByConcurrent(nums, numOfThreads, comparator)
result := slice.UniqueByConcurrent(nums,comparator, 4)
fmt.Println(result)
// Output:

View File

@@ -186,6 +186,7 @@ func RandStringSlice(charset string, sliceLen, strLen int) []string {
}
// RandFromGivenSlice generate a random element from given slice.
// Play: todo
func RandFromGivenSlice[T any](slice []T) T {
if len(slice) == 0 {
var zero T
@@ -194,6 +195,35 @@ func RandFromGivenSlice[T any](slice []T) T {
return slice[rand.Intn(len(slice))]
}
// RandSliceFromGivenSlice generate a random slice of length num from given slice.
// - If repeatable is true, the generated slice may contain duplicate elements.
//
// Play: todo
func RandSliceFromGivenSlice[T any](slice []T, num int, repeatable bool) []T {
if num <= 0 || len(slice) == 0 {
return slice
}
if !repeatable && num > len(slice) {
num = len(slice)
}
result := make([]T, num)
if repeatable {
for i := range result {
result[i] = slice[rand.Intn(len(slice))]
}
} else {
shuffled := make([]T, len(slice))
copy(shuffled, slice)
rand.Shuffle(len(shuffled), func(i, j int) {
shuffled[i], shuffled[j] = shuffled[j], shuffled[i]
})
result = shuffled[:num]
}
return result
}
// RandUpper generate a random upper case string of specified length.
// Play: https://go.dev/play/p/29QfOh0DVuh
func RandUpper(length int) string {

View File

@@ -47,18 +47,15 @@ func ExampleRandFromGivenSlice() {
goods := []string{"apple", "banana", "cherry", "elderberry", "fig", "grape", "honeydew", "kiwi", "lemon",
"mango", "nectarine", "orange"}
isInGoods := false
result := RandFromGivenSlice(goods)
for _, good := range goods {
if good == result {
isInGoods = true
break
}
}
fmt.Println(isInGoods)
fmt.Println(result)
}
// Output:
// true
func ExampleRandSliceFromGivenSlice() {
goods := []string{"apple", "banana", "cherry", "elderberry", "fig", "grape", "honeydew", "kiwi", "lemon",
"mango", "nectarine", "orange"}
chosen3goods := RandSliceFromGivenSlice(goods, 3, false)
fmt.Println(chosen3goods)
}
func ExampleRandUpper() {

View File

@@ -292,6 +292,46 @@ func TestRandFromGivenSlice(t *testing.T) {
assert.Equal(0, emtpyIntResult)
}
func TestRandSliceFromGivenSlice(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRandSliceFromGivenSlice")
randomSet := []any{"a", 8, "王", true, 1.1}
repeatableResult := RandSliceFromGivenSlice(randomSet, 8, true)
assert.Equal(8, len(repeatableResult))
unrepeatableResult := RandSliceFromGivenSlice(randomSet, 8, false)
assert.Equal(len(randomSet), len(unrepeatableResult))
var findCount int
for _, v := range repeatableResult {
for _, vv := range randomSet {
if v == vv {
findCount++
}
}
}
assert.Equal(8, findCount)
findCount = 0
for _, v := range unrepeatableResult {
for _, vv := range randomSet {
if v == vv {
findCount++
}
}
}
assert.Equal(len(randomSet), findCount)
emptyAnyRandomSet := []any{}
emptyAnyResult := RandSliceFromGivenSlice(emptyAnyRandomSet, 3, true)
assert.Equal([]any{}, emptyAnyResult)
emptyIntRandomSet := []int{}
emtpyIntResult := RandSliceFromGivenSlice(emptyIntRandomSet, 3, true)
assert.Equal([]int{}, emtpyIntResult)
}
func TestRandBool(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestRandBool")

View File

@@ -8,13 +8,54 @@ import (
"sync"
)
// ForEachConcurrent applies the iteratee function to each item in the slice concurrently.
// Play: todo
func ForEachConcurrent[T any](slice []T, iteratee func(index int, item T), numThreads int) {
sliceLen := len(slice)
if sliceLen == 0 {
return
}
if numThreads <= 0 {
numThreads = 1
}
var wg sync.WaitGroup
chunkSize := (sliceLen + numThreads - 1) / numThreads
for i := 0; i < numThreads; i++ {
start := i * chunkSize
end := start + chunkSize
if start >= sliceLen {
break
}
if end > sliceLen {
end = sliceLen
}
wg.Add(1)
go func(start, end int) {
defer wg.Done()
for j := start; j < end; j++ {
iteratee(j, slice[j])
}
}(start, end)
}
wg.Wait()
}
// 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 {
func MapConcurrent[T any, U any](slice []T, iteratee func(index int, item T) U, numThreads int) []U {
result := make([]U, len(slice))
var wg sync.WaitGroup
workerChan := make(chan struct{}, numOfThreads)
workerChan := make(chan struct{}, numThreads)
for index, item := range slice {
wg.Add(1)
@@ -35,13 +76,57 @@ func MapConcurrent[T any, U any](slice []T, numOfThreads int, iteratee func(inde
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.
// Play: todo
func FilterConcurrent[T any](slice []T, numOfThreads int, predicate func(index int, item T) bool) []T {
func FilterConcurrent[T any](slice []T, predicate func(index int, item T) bool, numThreads int) []T {
result := make([]T, 0)
var wg sync.WaitGroup
workerChan := make(chan struct{}, numOfThreads)
workerChan := make(chan struct{}, numThreads)
for index, item := range slice {
wg.Add(1)
@@ -66,20 +151,20 @@ func FilterConcurrent[T any](slice []T, numOfThreads int, predicate func(index i
// 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
// If numOfThreads is less than or equal to 0, it will be set to 1
// The numThreads parameter specifies the number of threads to use
// If numThreads is less than or equal to 0, it will be set to 1
// The comparator function should return true if the two elements are equal
// Play: todo
func UniqueByConcurrent[T comparable](slice []T, numOfThreads int, comparator func(item T, other T) bool) []T {
if numOfThreads <= 0 {
numOfThreads = 1
} else if numOfThreads > len(slice) {
numOfThreads = len(slice)
func UniqueByConcurrent[T comparable](slice []T, comparator func(item T, other T) bool, numThreads int) []T {
if numThreads <= 0 {
numThreads = 1
} else if numThreads > len(slice) {
numThreads = len(slice)
}
maxThreads := runtime.NumCPU()
if numOfThreads > maxThreads {
numOfThreads = maxThreads
if numThreads > maxThreads {
numThreads = maxThreads
}
removeDuplicate := func(items []T, comparator func(item T, other T) bool) []T {
@@ -99,9 +184,9 @@ func UniqueByConcurrent[T comparable](slice []T, numOfThreads int, comparator fu
return result
}
chunkSize := (len(slice) + numOfThreads - 1) / numOfThreads
chunkSize := (len(slice) + numThreads - 1) / numThreads
chunks := make([][]T, 0, numOfThreads)
chunks := make([][]T, 0, numThreads)
for i := 0; i < len(slice); i += chunkSize {
end := i + chunkSize
if end > len(slice) {
@@ -114,7 +199,7 @@ func UniqueByConcurrent[T comparable](slice []T, numOfThreads int, comparator fu
index int
data []T
}
resultCh := make(chan resultChunk, numOfThreads)
resultCh := make(chan resultChunk, numThreads)
var wg sync.WaitGroup
for i, chunk := range chunks {

View File

@@ -254,7 +254,7 @@ func ExampleFilterConcurrent() {
return num%2 == 0
}
result := FilterConcurrent(nums, 2, isEven)
result := FilterConcurrent(nums, isEven, 2)
fmt.Println(result)
@@ -429,6 +429,23 @@ func ExampleForEach() {
// [2 3 4]
}
func ExampleForEachConcurrent() {
nums := []int{1, 2, 3, 4, 5, 6, 7, 8}
result := make([]int, len(nums))
addOne := func(index int, value int) {
result[index] = value + 1
}
ForEachConcurrent(nums, addOne, 4)
fmt.Println(result)
// Output:
// [2 3 4 5 6 7 8 9]
}
func ExampleForEachWithBreak() {
numbers := []int{1, 2, 3, 4, 5}
@@ -510,6 +527,18 @@ func ExampleReduce() {
// 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() {
result1 := ReduceBy([]int{1, 2, 3, 4}, 0, func(_ int, item int, agg int) int {
return agg + item
@@ -1203,10 +1232,9 @@ func ExampleLeftPadding() {
func ExampleUniqueByConcurrent() {
nums := []int{1, 2, 3, 1, 2, 4, 5, 6, 4, 7}
numOfThreads := 4
comparator := func(item int, other int) bool { return item == other }
result := UniqueByConcurrent(nums, numOfThreads, comparator)
result := UniqueByConcurrent(nums, comparator, 4)
fmt.Println(result)
@@ -1216,7 +1244,7 @@ func ExampleUniqueByConcurrent() {
func ExampleMapConcurrent() {
nums := []int{1, 2, 3, 4, 5, 6}
result := MapConcurrent(nums, 4, func(_, n int) int { return n * n })
result := MapConcurrent(nums, func(_, n int) int { return n * n }, 4)
fmt.Println(result)

View File

@@ -410,6 +410,73 @@ func TestForEach(t *testing.T) {
assert.Equal([]int{3, 4, 5, 6, 7}, result)
}
func TestForEachConcurrent(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestForEachConcurrent")
t.Run("single thread", func(t *testing.T) {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
result := make([]int, len(numbers))
addOne := func(index int, value int) {
result[index] = value + 1
}
ForEachConcurrent(numbers, addOne, 1)
expected := []int{2, 3, 4, 5, 6, 7, 8, 9, 10}
assert.Equal(expected, result)
})
t.Run("normal", func(t *testing.T) {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
result := make([]int, len(numbers))
addOne := func(index int, value int) {
result[index] = value + 1
}
ForEachConcurrent(numbers, addOne, 4)
expected := []int{2, 3, 4, 5, 6, 7, 8, 9, 10}
assert.Equal(expected, result)
})
t.Run("negative threads", func(t *testing.T) {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
result := make([]int, len(numbers))
addOne := func(index int, value int) {
result[index] = value + 1
}
ForEachConcurrent(numbers, addOne, -4)
expected := []int{2, 3, 4, 5, 6, 7, 8, 9, 10}
assert.Equal(expected, result)
})
t.Run("high number threads", func(t *testing.T) {
numbers := make([]int, 1000)
for i := range numbers {
numbers[i] = i
}
result := make([]int, len(numbers))
addOne := func(index int, value int) {
result[index] = value + 1
}
ForEachConcurrent(numbers, addOne, 50)
for i, item := range numbers {
assert.Equal(item+1, result[i])
}
})
}
func TestForEachWithBreak(t *testing.T) {
t.Parallel()
@@ -520,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) {
t.Parallel()
@@ -1509,10 +1614,9 @@ func TestUniqueByConcurrent(t *testing.T) {
assert := internal.NewAssert(t, "TestUniqueByConcurrent")
nums := []int{1, 2, 3, 1, 2, 4, 5, 6, 4, 7}
numOfThreads := 4
comparator := func(item int, other int) bool { return item == other }
result := UniqueByConcurrent(nums, numOfThreads, comparator)
result := UniqueByConcurrent(nums, comparator, 4)
assert.Equal([]int{1, 2, 3, 4, 5, 6, 7}, result)
}
@@ -1523,21 +1627,21 @@ func TestMapConcurrent(t *testing.T) {
assert := internal.NewAssert(t, "TestMapConcurrent")
t.Run("empty slice", func(t *testing.T) {
actual := MapConcurrent([]int{}, 4, func(_, n int) int { return n * n })
actual := MapConcurrent([]int{}, func(_, n int) int { return n * n }, 4)
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 })
actual := MapConcurrent(nums, func(_, n int) int { return n * n }, 1)
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 })
actual := MapConcurrent(nums, func(_, n int) int { return n * n }, 4)
assert.Equal(expected, actual)
})
@@ -1549,21 +1653,21 @@ func TestFilterConcurrent(t *testing.T) {
assert := internal.NewAssert(t, "TestFilterConcurrent")
t.Run("empty slice", func(t *testing.T) {
actual := FilterConcurrent([]int{}, 4, func(_, n int) bool { return n != 0 })
actual := FilterConcurrent([]int{}, func(_, n int) bool { return n != 0 }, 4)
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 })
actual := FilterConcurrent(nums, func(_, n int) bool { return n > 3 }, 1)
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 })
actual := FilterConcurrent(nums, func(_, n int) bool { return n > 3 }, 4)
assert.Equal(expected, actual)
})