Skip to content

Commit

Permalink
feat: Add Union method and typesafe UnionStringMap
Browse files Browse the repository at this point in the history
  • Loading branch information
adammw committed Nov 25, 2021
1 parent 658cf47 commit bd4dd26
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 0 deletions.
67 changes: 67 additions & 0 deletions union.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package funk

import (
"reflect"
)

// Union returns the union between two collections.
func Union(collections ...interface{}) interface{} {
// shortcut zero/single argument
if len(collections) == 0 {
return nil
} else if len(collections) == 1 {
return collections[0]
}

if !IsIteratee(collections[0]) {
panic("Parameter must be a collection")
}

cType := reflect.TypeOf(collections[0])
zLen := 0

for i, x := range collections {
xValue := reflect.ValueOf(x)
xType := xValue.Type()
if i > 0 && NotEqual(cType, xType) {
panic("Parameters must have the same type")
}

zLen += xValue.Len()
}

if cType.Kind() == reflect.Map {
zType := reflect.MapOf(cType.Key(), cType.Elem())
zMap := reflect.MakeMap(zType)

for _, x := range collections {
xIter := reflect.ValueOf(x).MapRange()
for xIter.Next() {
zMap.SetMapIndex(xIter.Key(), xIter.Value())
}
}

return zMap.Interface()
} else {
zType := reflect.SliceOf(cType.Elem())
zSlice := reflect.MakeSlice(zType, 0, 0)

for _, x := range collections {
xValue := reflect.ValueOf(x)
zSlice = reflect.AppendSlice(zSlice, xValue)
}

return zSlice.Interface()
}
}

// UnionStringMap returns the union between multiple string maps
func UnionStringMap(x ...map[string]string) map[string]string {
zMap := map[string]string{}
for _, xMap := range x {
for k, v := range xMap {
zMap[k] = v
}
}
return zMap
}
34 changes: 34 additions & 0 deletions union_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package funk

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestUnion(t *testing.T) {
is := assert.New(t)

r := Union([]int{1, 2, 3, 4}, []int{2, 4, 6})
is.Equal(r, []int{1, 2, 3, 4, 2, 4, 6})

r = Union(map[int]int{1: 1, 2: 2}, map[int]int{1: 0, 3: 3})
is.Equal(r, map[int]int{1: 0, 2: 2, 3: 3})
}

func TestUnionShortcut(t *testing.T) {
is := assert.New(t)

r := Union(nil)
is.Nil(r)

r = Union([]int{1, 2})
is.Equal(r, []int{1, 2})
}

func TestUnionStringMap(t *testing.T) {
is := assert.New(t)

r := Union(map[string]string{"a": "a", "b": "b"}, map[string]string{"a": "z", "z": "a"}, map[string]string{"z": "z"})
is.Equal(r, map[string]string{"a": "z", "b": "b", "z": "z"})
}

0 comments on commit bd4dd26

Please sign in to comment.