diff --git a/Changes.md b/Changes.md index c819182..6f156ed 100644 --- a/Changes.md +++ b/Changes.md @@ -2,6 +2,7 @@ WIP TBD * Added slices.FirstIndex and slices.GrepIndex. * Added set.NewSized and set.Diff. + * Added maps.Diff. * Fixed missing test coverage on generic.FirstNonNil and generic.FirstNonZero. v0.2.0 2023-07-08 diff --git a/README.md b/README.md index 9e8cdc7..e957237 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ There are a lot of common map operations that are missing from the built-in standard library: * `Merge(...maps)` + * `Diff(a, b)` ## Generic Sets diff --git a/maps/merge.go b/maps/merge.go index 7a512c4..1e1abb4 100644 --- a/maps/merge.go +++ b/maps/merge.go @@ -1,5 +1,7 @@ package maps +import "github.com/zostay/go-std/generic" + // Merge maps into a single map. Keys in maps later in the list will overwrite // keys found in earlier maps. func Merge[K comparable, V any](maps ...map[K]V) map[K]V { @@ -11,3 +13,33 @@ func Merge[K comparable, V any](maps ...map[K]V) map[K]V { } return out } + +// Diff returns three maps from two. The first map returned is a map of +// key/value pairs where the keys are found in both the first and second input +// maps. The second map returned contains a map of key/value pairs for keys only +// found in the first map. The third map returned contains a map of key/value +// pairs for keys only found in the third map. +// +// If values differ for keys held in common, the value in the first input map +// are kept. +func Diff[K comparable, V any](a, b map[K]V) (common, inFirst, inSecond map[K]V) { + common = make(map[K]V, generic.Max(len(a), len(b))) + inFirst = make(map[K]V, len(a)) + inSecond = make(map[K]V, len(b)) + + for akey, avalue := range a { + if _, found := b[akey]; found { + common[akey] = avalue + } else { + inFirst[akey] = avalue + } + } + + for bkey, bvalue := range b { + if _, found := a[bkey]; !found { + inSecond[bkey] = bvalue + } + } + + return +} diff --git a/maps/merge_test.go b/maps/merge_test.go index 08f0e51..573453d 100644 --- a/maps/merge_test.go +++ b/maps/merge_test.go @@ -27,3 +27,13 @@ func TestMerge(t *testing.T) { "a": 5, "b": 6, "c": 7, "d": 4, }, maps.Merge(a, b, c)) } + +func TestDiff(t *testing.T) { + a := map[string]int{"one": 1, "two": 2, "three": 3, "four": 4} + b := map[string]int{"one": 5, "three": 6, "five": 7, "seven": 8} + + c, one, two := maps.Diff(a, b) + assert.Equal(t, map[string]int{"one": 1, "three": 3}, c) + assert.Equal(t, map[string]int{"two": 2, "four": 4}, one) + assert.Equal(t, map[string]int{"five": 7, "seven": 8}, two) +}