Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DifferenceBy for slices with any types #456

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
34 changes: 34 additions & 0 deletions intersect.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
29 changes: 29 additions & 0 deletions intersect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down