From 65a254e84f326d610b9a374fb68ae07b5b7be2e2 Mon Sep 17 00:00:00 2001 From: Adrien Pensart Date: Thu, 18 Jan 2024 08:45:03 -0500 Subject: [PATCH] add intersect.SymmetricDifference --- README.md | 16 ++++++++++++++++ intersect.go | 32 ++++++++++++++++++++++++++++++++ intersect_test.go | 15 +++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/README.md b/README.md index dd848c39..e126e8a3 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,7 @@ Supported intersection helpers: - [NoneBy](#noneby) - [Intersect](#intersect) - [Difference](#difference) +- [SymmetricDifference](#symmetric_difference) - [Union](#union) - [Without](#without) - [WithoutEmpty](#withoutempty) @@ -1720,6 +1721,21 @@ left, right := lo.Difference([]int{0, 1, 2, 3, 4, 5}, []int{0, 1, 2, 3, 4, 5}) // []int{}, []int{} ``` +### SymmetricDifference + +Returns the symmetric difference between two collections. + +Returns all elements which are in either of the collections but not in both. +Does not preserve order of elements. + +```go +diff := SymmetricDifference([]int{0, 1, 2, 3, 4, 5}, []int{0, 2, 6}) +// []int{1, 3, 4, 5, 6} + +diff := SymmetricDifference([]int{0, 1, 2, 3, 4, 5}, []int{0, 1, 2, 3, 4, 5}) +// []int{} +``` + ### Union Returns all distinct elements from given collections. Result will not change the order of elements relatively. diff --git a/intersect.go b/intersect.go index cf6cab3d..bc916f12 100644 --- a/intersect.go +++ b/intersect.go @@ -141,6 +141,38 @@ func Difference[T comparable](list1 []T, list2 []T) ([]T, []T) { return left, right } +// Symmetric difference returns the elements presents in one collection +// but not in the other +// Order is not preserved +func SymmetricDifference[T comparable](list1 []T, list2 []T) []T { + diff := []T{} + + seenLeft := map[T]struct{}{} + seenRight := map[T]struct{}{} + + for _, elem := range list1 { + seenLeft[elem] = struct{}{} + } + + for _, elem := range list2 { + seenRight[elem] = struct{}{} + } + + for _, elem := range list1 { + if _, ok := seenRight[elem]; !ok { + diff = append(diff, elem) + } + } + + for _, elem := range list2 { + if _, ok := seenLeft[elem]; !ok { + diff = append(diff, elem) + } + } + + return diff +} + // Union returns all distinct elements from given collections. // result returns will not change the order of elements relatively. func Union[T comparable](lists ...[]T) []T { diff --git a/intersect_test.go b/intersect_test.go index 339dbcbb..f8cd806c 100644 --- a/intersect_test.go +++ b/intersect_test.go @@ -206,6 +206,21 @@ func TestDifference(t *testing.T) { is.Equal(right3, []int{}) } +func TestSymmetricDifference(t *testing.T) { + t.Parallel() + is := assert.New(t) + + diff1 := SymmetricDifference([]int{0, 1, 2, 3, 4, 5}, []int{0, 2, 6}) + is.ElementsMatch(diff1, []int{1, 3, 4, 5, 6}) + + diff2 := SymmetricDifference([]int{1, 2, 3, 4, 5}, []int{0, 6}) + is.ElementsMatch(diff2, []int{0, 1, 2, 3, 4, 5, 6}) + + diff3 := SymmetricDifference([]int{0, 1, 2, 3, 4, 5}, []int{0, 1, 2, 3, 4, 5}) + is.ElementsMatch(diff3, []int{}) +} + + func TestUnion(t *testing.T) { t.Parallel() is := assert.New(t)