Feature/intersect by (#653)

* Update README.md

Fixed the error in the usage example of lo.Latest in readme.md

use []time.Time{…} (value of type []time.Time) as time.Time value in argument to lo.Latest

* Update README.md

* feature: add Mode function with tests and documentation

* feat: Add IntersectBy function and tests, supporting intersection by custom key sets

---------

Co-authored-by: Samuel Berthe <dev@samuel-berthe.fr>
This commit is contained in:
ghosx
2025-11-07 04:14:54 +08:00
committed by GitHub
parent 4e2c33e8a4
commit 43ae3d74da
2 changed files with 62 additions and 0 deletions
+21
View File
@@ -170,6 +170,27 @@ func Intersect[T comparable, Slice ~[]T](lists ...Slice) Slice {
return Slice{}
}
// IntersectBy returns the intersection between two collections using a custom key selector function.
// It preserves the order of elements from the second list (list2).
func IntersectBy[T any, K comparable, Slice ~[]T](list1 Slice, list2 Slice, iteratee func(T) K) Slice {
result := make(Slice, 0)
seen := make(map[K]struct{})
for _, item := range list1 {
key := iteratee(item)
seen[key] = struct{}{}
}
for _, item := range list2 {
key := iteratee(item)
if _, exists := seen[key]; exists {
result = append(result, item)
}
}
return result
}
// Difference returns the difference between two collections.
// The first value is the collection of elements absent from list2.
// The second value is the collection of elements absent from list1.
+41
View File
@@ -1,6 +1,7 @@
package lo
import (
"strconv"
"testing"
"github.com/stretchr/testify/assert"
@@ -204,6 +205,46 @@ func TestIntersect(t *testing.T) {
is.IsType(nonempty, allStrings, "type preserved")
}
func TestIntersectBy(t *testing.T) {
t.Parallel()
is := assert.New(t)
type User struct {
ID int
Name string
}
list1 := []User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
{ID: 3, Name: "Charlie"},
}
list2 := []User{
{ID: 2, Name: "Robert"},
{ID: 3, Name: "Charlie"},
{ID: 4, Name: "Alice"},
}
intersectByID := IntersectBy(list1, list2, func(u User) int {
return u.ID
})
is.Equal(intersectByID, []User{{ID: 2, Name: "Robert"}, {ID: 3, Name: "Charlie"}})
// output: [{2 Robert} {3 Charlie}]
intersectByName := IntersectBy(list1, list2, func(u User) string {
return u.Name
})
is.Equal(intersectByName, []User{{ID: 3, Name: "Charlie"}, {ID: 4, Name: "Alice"}})
// output: [{3 Charlie} {4 Alice}]
intersectByIDAndName := IntersectBy(list1, list2, func(u User) string {
return strconv.Itoa(u.ID) + u.Name
})
is.Equal(intersectByIDAndName, []User{{ID: 3, Name: "Charlie"}})
// output: [{3 Charlie}]
}
func TestDifference(t *testing.T) {
t.Parallel()
is := assert.New(t)