From 3fd38d149783f36b4b39b19a6ade55830abc1220 Mon Sep 17 00:00:00 2001 From: Misha Dolbnin Date: Wed, 31 Jan 2024 22:39:25 +0000 Subject: [PATCH 1/2] add DifferenceBy for non-comparable types --- intersect.go | 34 ++++++++++++++++++++++++++++++++++ intersect_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/intersect.go b/intersect.go index cf6cab3d..dd151650 100644 --- a/intersect.go +++ b/intersect.go @@ -141,6 +141,40 @@ func Difference[T comparable](list1 []T, list2 []T) ([]T, []T) { return left, right } +// DifferenceBy returns the difference between two collections by callback. +// The first value is the collection of element absent of list2. +// The second value is the collection of element absent of list1. +// Callback used to transform non-comparable into comparable +func DifferenceBy[T comparable, V any](list1, list2 []V, callback func(item V) T) ([]V, []V) { + left := make([]V, 0) + right := make([]V, 0) + + seenLeft := map[T]struct{}{} + seenRight := map[T]struct{}{} + + for _, elem := range list1 { + seenLeft[callback(elem)] = struct{}{} + } + + for _, elem := range list2 { + seenRight[callback(elem)] = struct{}{} + } + + for _, elem := range list1 { + if _, ok := seenRight[callback(elem)]; !ok { + left = append(left, elem) + } + } + + for _, elem := range list2 { + if _, ok := seenLeft[callback(elem)]; !ok { + right = append(right, elem) + } + } + + return left, right +} + // 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..4fd7abde 100644 --- a/intersect_test.go +++ b/intersect_test.go @@ -206,6 +206,35 @@ func TestDifference(t *testing.T) { is.Equal(right3, []int{}) } +func TestDifferenceBy(t *testing.T) { + t.Parallel() + is := assert.New(t) + + left1, right1 := DifferenceBy([]int{0, 1, 2, 3, 4, 5}, []int{0, 2, 6}, func(item int) int { + return item + }) + is.Equal(left1, []int{1, 3, 4, 5}) + is.Equal(right1, []int{6}) + + left2, right2 := DifferenceBy([]int{1, 2, 3, 4, 5}, []int{0, 6}, func(item int) int { + return item + }) + is.Equal(left2, []int{1, 2, 3, 4, 5}) + is.Equal(right2, []int{0, 6}) + + left3, right3 := DifferenceBy([]int{0, 1, 2, 3, 4, 5}, []int{0, 1, 2, 3, 4, 5}, func(item int) int { + return item + }) + is.Equal(left3, []int{}) + is.Equal(right3, []int{}) + + left4, right4 := DifferenceBy([][]int{{1}, {2}}, [][]int{{0}, {1}}, func(item []int) int { + return item[0] + }) + is.Equal(left4, [][]int{{2}}) + is.Equal(right4, [][]int{{0}}) +} + func TestUnion(t *testing.T) { t.Parallel() is := assert.New(t) From 1e0b097a014e030fee3647d8f7333befee7f909c Mon Sep 17 00:00:00 2001 From: yesmishgan Date: Sat, 18 May 2024 22:43:31 +0300 Subject: [PATCH 2/2] update README for DifferenceBy --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index dd848c39..5c3a67cb 100644 --- a/README.md +++ b/README.md @@ -1720,6 +1720,23 @@ left, right := lo.Difference([]int{0, 1, 2, 3, 4, 5}, []int{0, 1, 2, 3, 4, 5}) // []int{}, []int{} ``` +### DifferenceBy + +Returns the difference between two collections by callback func. + +- The first value is the collection of element absent of list2. +- The second value is the collection of element absent of list1. + +```go +left, right := lo.DifferenceBy([]int{0, 1, 2, 3, 4, 5}, []int{0, 2, 6}) +// []int{1, 3, 4, 5}, []int{6} + +left, right := lo.DifferenceBy([][]int{{1}, {2}}, [][]int{{0}, {1}}, func(item []int) int { +return item[0] +}) +// [][]int{{2}}, [][]int{{0}} +``` + ### Union Returns all distinct elements from given collections. Result will not change the order of elements relatively.