mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-04 12:52:28 +08:00
feat: add UniqueByField
This commit is contained in:
@@ -796,6 +796,46 @@ func UniqueBy[T comparable](slice []T, iteratee func(item T) T) []T {
|
|||||||
return Unique(result)
|
return Unique(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UniqueByField remove duplicate elements in struct slice by struct field.
|
||||||
|
// Play: todo
|
||||||
|
func UniqueByField[T any](slice []T, field string) ([]T, error) {
|
||||||
|
seen := map[any]struct{}{}
|
||||||
|
|
||||||
|
var result []T
|
||||||
|
for _, item := range slice {
|
||||||
|
val, err := getField(item, field)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("get field %s failed: %v", field, err)
|
||||||
|
}
|
||||||
|
if _, ok := seen[val]; !ok {
|
||||||
|
seen[val] = struct{}{}
|
||||||
|
result = append(result, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getField[T any](item T, field string) (interface{}, error) {
|
||||||
|
v := reflect.ValueOf(item)
|
||||||
|
t := reflect.TypeOf(item)
|
||||||
|
|
||||||
|
if t.Kind() == reflect.Ptr {
|
||||||
|
t = t.Elem()
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
if v.Kind() != reflect.Struct {
|
||||||
|
return nil, fmt.Errorf("data type %T not support, shuld be struct or pointer to struct", item)
|
||||||
|
}
|
||||||
|
|
||||||
|
f := v.FieldByName(field)
|
||||||
|
if !f.IsValid() {
|
||||||
|
return nil, fmt.Errorf("field name %s not found", field)
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.FieldByName(field).Interface(), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Union creates a slice of unique elements, in order, from all given slices.
|
// Union creates a slice of unique elements, in order, from all given slices.
|
||||||
// Play: https://go.dev/play/p/hfXV1iRIZOf
|
// Play: https://go.dev/play/p/hfXV1iRIZOf
|
||||||
func Union[T comparable](slices ...[]T) []T {
|
func Union[T comparable](slices ...[]T) []T {
|
||||||
|
|||||||
@@ -780,6 +780,28 @@ func ExampleUniqueBy() {
|
|||||||
// [1 2 0]
|
// [1 2 0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleUniqueByField() {
|
||||||
|
type User struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
users := []User{
|
||||||
|
{ID: 1, Name: "a"},
|
||||||
|
{ID: 2, Name: "b"},
|
||||||
|
{ID: 1, Name: "c"},
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := UniqueByField(users, "ID")
|
||||||
|
if err != nil {
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(result)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// [{1 a} {2 b}]
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleUnion() {
|
func ExampleUnion() {
|
||||||
nums1 := []int{1, 3, 4, 6}
|
nums1 := []int{1, 3, 4, 6}
|
||||||
nums2 := []int{1, 2, 5, 6}
|
nums2 := []int{1, 2, 5, 6}
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ package slice
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/duke-git/lancet/v2/internal"
|
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestContain(t *testing.T) {
|
func TestContain(t *testing.T) {
|
||||||
@@ -735,6 +736,33 @@ func TestUniqueBy(t *testing.T) {
|
|||||||
assert.Equal([]int{1, 2, 3, 0}, actual)
|
assert.Equal([]int{1, 2, 3, 0}, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUniqueByField(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
assert := internal.NewAssert(t, "TestUniqueByField")
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
users := []User{
|
||||||
|
{ID: 1, Name: "a"},
|
||||||
|
{ID: 2, Name: "b"},
|
||||||
|
{ID: 1, Name: "c"},
|
||||||
|
}
|
||||||
|
|
||||||
|
uniqueUsers, err := UniqueByField(users, "ID")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal([]User{
|
||||||
|
{ID: 1, Name: "a"},
|
||||||
|
{ID: 2, Name: "b"},
|
||||||
|
}, uniqueUsers)
|
||||||
|
}
|
||||||
|
|
||||||
func TestUnion(t *testing.T) {
|
func TestUnion(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user