Skip to content

Commit

Permalink
preallocate stuff and more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
samber committed Aug 11, 2024
1 parent d9d3e3f commit cd0bc21
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 64 deletions.
62 changes: 0 additions & 62 deletions benchmark_test.go

This file was deleted.

14 changes: 12 additions & 2 deletions map.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ func Keys[K comparable, V any](in ...map[K]V) []K {
// UniqKeys creates an array of unique keys in the map.
// Play: https://go.dev/play/p/TPKAb6ILdHk
func UniqKeys[K comparable, V any](in ...map[K]V) []K {
seen := make(map[K]struct{})
size := 0
for i := range in {
size += len(in[i])
}

seen := make(map[K]struct{}, size)
result := make([]K, 0)

for i := range in {
Expand Down Expand Up @@ -65,7 +70,12 @@ func Values[K comparable, V any](in ...map[K]V) []V {
// UniqValues creates an array of unique values in the map.
// Play: https://go.dev/play/p/nf6bXMh7rM3
func UniqValues[K comparable, V comparable](in ...map[K]V) []V {
seen := make(map[V]struct{})
size := 0
for i := range in {
size += len(in[i])
}

seen := make(map[V]struct{}, size)
result := make([]V, 0)

for i := range in {
Expand Down
124 changes: 124 additions & 0 deletions map_benchmark_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package lo

import (
"math/rand"
"strconv"
"testing"
"time"

lop "github.com/samber/lo/parallel"
"github.com/thoas/go-funk"
)

func sliceGenerator(size uint) []int64 {
r := rand.New(rand.NewSource(time.Now().Unix()))

result := make([]int64, size)

for i := uint(0); i < size; i++ {
result[i] = r.Int63()
}

return result
}

func mapGenerator(size uint) map[int64]int64 {
r := rand.New(rand.NewSource(time.Now().Unix()))

result := make(map[int64]int64, size)

for i := uint(0); i < size; i++ {
result[int64(i)] = r.Int63()
}

return result
}

func BenchmarkMap(b *testing.B) {
arr := sliceGenerator(1000000)

b.Run("lo.Map", func(b *testing.B) {
for n := 0; n < b.N; n++ {
_ = Map(arr, func(x int64, i int) string {
return strconv.FormatInt(x, 10)
})
}
})

b.Run("lop.Map", func(b *testing.B) {
for n := 0; n < b.N; n++ {
_ = lop.Map(arr, func(x int64, i int) string {
return strconv.FormatInt(x, 10)
})
}
})

b.Run("reflect", func(b *testing.B) {
for n := 0; n < b.N; n++ {
_ = funk.Map(arr, func(x int64) string {
return strconv.FormatInt(x, 10)
})
}
})

b.Run("for", func(b *testing.B) {
for n := 0; n < b.N; n++ {
results := make([]string, len(arr))

for i, item := range arr {
result := strconv.FormatInt(item, 10)
results[i] = result
}
}
})
}

// also apply to UniqValues
func BenchmarkUniqKeys(b *testing.B) {
m := []map[int64]int64{
mapGenerator(100000),
mapGenerator(100000),
mapGenerator(100000),
}

// allocate just in time + ordered
b.Run("lo.UniqKeys.jit-alloc", func(b *testing.B) {
for n := 0; n < b.N; n++ {
seen := make(map[int64]struct{})
result := make([]int64, 0)

for i := range m {
for k := range m[i] {
if _, exists := seen[k]; exists {
continue
}
seen[k] = struct{}{}
result = append(result, k)

Check failure on line 96 in map_benchmark_test.go

View workflow job for this annotation

GitHub Actions / lint

SA4010: this result of append is never used, except maybe in other appends (staticcheck)
}
}
}
})

// preallocate + unordered
b.Run("lo.UniqKeys.preallocate", func(b *testing.B) {
for n := 0; n < b.N; n++ {
size := 0
for i := range m {
size += len(m[i])
}
seen := make(map[int64]struct{}, size)

for i := range m {
for k := range m[i] {
seen[k] = struct{}{}
}
}

result := make([]int64, 0, len(seen))

for k := range seen {
result = append(result, k)

Check failure on line 120 in map_benchmark_test.go

View workflow job for this annotation

GitHub Actions / lint

SA4010: this result of append is never used, except maybe in other appends (staticcheck)
}
}
})
}
8 changes: 8 additions & 0 deletions map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ func TestUniqKeys(t *testing.T) {
r5 := UniqKeys(map[string]int{"foo": 1, "bar": 2}, map[string]int{"foo": 1, "bar": 3})
sort.Strings(r5)
is.Equal(r5, []string{"bar", "foo"})

// check order
r6 := UniqKeys(map[string]int{"foo": 1}, map[string]int{"bar": 3})
is.Equal(r6, []string{"foo", "bar"})
}

func TestHasKey(t *testing.T) {
Expand Down Expand Up @@ -114,6 +118,10 @@ func TestUniqValues(t *testing.T) {
r6 := UniqValues(map[string]int{"foo": 1, "bar": 1}, map[string]int{"foo": 1, "bar": 3})
sort.Ints(r6)
is.Equal(r6, []int{1, 3})

// check order
r7 := UniqValues(map[string]int{"foo": 1}, map[string]int{"bar": 3})
is.Equal(r7, []int{1, 3})
}

func TestValueOr(t *testing.T) {
Expand Down

0 comments on commit cd0bc21

Please sign in to comment.