diff --git a/README.md b/README.md index b1cdc7a..60ac388 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,10 @@ - Contains 包含某个元素 - ContainsAll 包含指定元素 - ContainsAny 包含任意元素 + - SameElements 两个切片是否拥有相同的元素,不考虑顺序,元素相同即可 + - Intersection 两个切片的交集 + - Union 两个切片的合集,如果遇到重复元素,只保留1个 + - Diff 两个切片的差集,以第一个参数为基准 - [x] 结构体相关操作 - JoinStructsField 将任意结构体切片中的指定字段的值使用英文逗号拼接成一个字符串,例如:用户列表中,所有用户ID拼成一个字符串 - PickStructsField 将任意结构体切片中的指定字段的值提取出来形成一个保持原类型的数组,例如:用户列表中,所有用户ID提取成一个用户ID数组 diff --git a/slice.go b/slice.go index c2be61d..724aa68 100644 --- a/slice.go +++ b/slice.go @@ -61,3 +61,66 @@ func ContainsAny[T any](data []T, elements []T) bool { } return false } + +// SameElements 两个切片是否拥有相同的元素,不考虑它们的顺序,只要元素相同即可 +func SameElements[T any](data1, data2 []T) bool { + if len(data1) != len(data2) { + return false + } + for _, datum1 := range data1 { + found := false + for _, datum2 := range data2 { + if reflect.DeepEqual(datum1, datum2) { + found = true + break + } + } + if !found { + return false + } + } + return true +} + +// Intersection 两个切片的交集 +func Intersection[T any](s1, s2 []T) (results []T) { + hash := make(map[any]bool) + for _, elem := range s1 { + hash[elem] = true + } + for _, elem := range s2 { + if hash[elem] { + results = append(results, elem) + } + } + return results +} + +// Union 两个切片的合集,如果遇到重复元素,只保留1个 +func Union[T any](s1, s2 []T) (results []T) { + hash := make(map[any]bool) + for _, elem := range s1 { + hash[elem] = true + } + for _, elem := range s2 { + hash[elem] = true + } + for elem := range hash { + results = append(results, elem.(T)) + } + return results +} + +// Diff 两个切片的差集,以第一个参数s1为基准,即:返回在s1中存在 且 在s2中不存在的元素集合 +func Diff[T any](s1, s2 []T) (results []T) { + hash := make(map[any]bool) + for _, elem := range s2 { + hash[elem] = true + } + for _, elem := range s1 { + if !hash[elem] { + results = append(results, elem) + } + } + return results +} diff --git a/slice_test.go b/slice_test.go index d23b4c4..83b5b42 100644 --- a/slice_test.go +++ b/slice_test.go @@ -225,3 +225,71 @@ func TestContainsAnyInteger(t *testing.T) { }) } } + +func TestSlice_Intersection_Union_Diff_Integer(t *testing.T) { + type args[T any] struct { + data1 []T + data2 []T + } + type testCase[T any] struct { + name string + args args[T] + intersectionWant []T + unionWant []T + diffWant []T + } + tests := []testCase[int]{ + { + name: "SliceIntersection_Union_Diff_Integer", + args: args[int]{data1: []int{1, 2, 3, 4}, data2: []int{1, 2, 8, 10}}, + intersectionWant: []int{1, 2}, + unionWant: []int{1, 2, 3, 4, 8, 10}, + diffWant: []int{3, 4}, + }, + } + for _, tt := range tests { + if got := Intersection[int](tt.args.data1, tt.args.data2); !SameElements(got, tt.intersectionWant) { + t.Errorf("Intersection() = %v, want %v", got, tt.intersectionWant) + } + if got := Union[int](tt.args.data1, tt.args.data2); !SameElements(got, tt.unionWant) { + t.Errorf("Union() = %v, want %v", got, tt.unionWant) + } + if got := Diff[int](tt.args.data1, tt.args.data2); !SameElements(got, tt.diffWant) { + t.Errorf("Diff() = %v, want %v", got, tt.diffWant) + } + } +} + +func TestSlice_Intersection_Union_Diff_String(t *testing.T) { + type args[T any] struct { + data1 []T + data2 []T + } + type testCase[T any] struct { + name string + args args[T] + intersectionWant []T + unionWant []T + diffWant []T + } + tests := []testCase[string]{ + { + name: "SliceIntersection_Union_Diff_String", + args: args[string]{data1: []string{"1", "2", "3", "4"}, data2: []string{"1", "2", "8", "10"}}, + intersectionWant: []string{"1", "2"}, + unionWant: []string{"1", "2", "3", "4", "8", "10"}, + diffWant: []string{"3", "4"}, + }, + } + for _, tt := range tests { + if got := Intersection[string](tt.args.data1, tt.args.data2); !SameElements(got, tt.intersectionWant) { + t.Errorf("Intersection() = %v, want %v", got, tt.intersectionWant) + } + if got := Union[string](tt.args.data1, tt.args.data2); !SameElements(got, tt.unionWant) { + t.Errorf("Union() = %v, want %v", got, tt.unionWant) + } + if got := Diff[string](tt.args.data1, tt.args.data2); !SameElements(got, tt.diffWant) { + t.Errorf("Diff() = %v, want %v", got, tt.diffWant) + } + } +}