避免代码里面单独写出长长的嵌套逻辑,容易遗漏的问题
计算集合
Left (Slice)和Right(Slice)
或者Left (Map)和Right(Map)
的补集和交集
leftComplementary =
rightComplementary =
intersection =
下面的工具用来计算两个slice的补集,交集是通用的计算代码,可以使用自定义的struct类型的slice数组
import (
"reflect"
)
type Pair struct {
Left interface{}
Right interface{}
}
type EqFunc func(leftItem interface{}, rightItem interface{}) bool
func DiffSliceCal(left, right interface{}, eq EqFunc) (leftComplementary, rightComplementary interface{}, intersection []Pair) {
checkSliceType(left, "left")
checkSliceType(right, "right")
leftSlice := reflect.ValueOf(left)
rightSlice := reflect.ValueOf(right)
intersection = make([]Pair, 0)
eqLeftMap := map[interface{}]int{}
eqRightMap := map[interface{}]int{}
for i := 0; i < leftSlice.Len(); i++ {
leftItem := leftSlice.Index(i).Interface()
for j := 0; j < rightSlice.Len(); j++ {
rightItem := rightSlice.Index(j).Interface()
if eq(leftItem, rightItem) {
intersection = append(intersection, Pair{
Left: leftItem,
Right: rightItem,
})
eqLeftMap[leftItem] = 1
eqRightMap[rightItem] = 1
}
}
}
leftComplementary = appendNotEqual(leftSlice, eqLeftMap)
rightComplementary = appendNotEqual(rightSlice, eqRightMap)
return
}
func appendNotEqual(sliceValue reflect.Value, eqMap map[interface{}]int) (ret interface{}) {
retSliceValue := reflect.MakeSlice(sliceValue.Type(), 0, sliceValue.Len())
for i := 0; i < sliceValue.Len(); i++ {
leftItemValue := sliceValue.Index(i)
leftItem := leftItemValue.Interface()
if _, exists := eqMap[leftItem]; !exists {
retSliceValue = reflect.Append(retSliceValue, leftItemValue)
}
}
ret = retSliceValue.Interface()
return
}
func checkSliceType(obj interface{}, prefix string) {
if reflect.TypeOf(obj).Kind() != reflect.Slice {
panic(prefix + " type not a slice ")
}
}
测试代码:
import (
"fmt"
"testing"
)
type FieldTest struct {
FieldID int64 `json:"field_id"`
Scope int `json:"scope"`
}
func Test_diffCal(t *testing.T) {
left := []FieldTest{{FieldID: 1}}
right := []FieldTest{{FieldID: 1}}
eqFuncTest := func(leftItem interface{}, rightItem interface{}) bool {
l := leftItem.(FieldTest)
r := rightItem.(FieldTest)
return l.FieldID == r.FieldID
}
leftComplementary, rightComplementary, intersection := DiffSliceCal(left, right, eqFuncTest)
fmt.Printf("leftComplementary:%v \n, rightComplementary:%v \n, intersection:%v \n-------------- \n", leftComplementary, rightComplementary, intersection)
left = []FieldTest{{FieldID: 1, Scope: 1}, {FieldID: 2, Scope: 1}, {FieldID: 3, Scope: 2}}
right = []FieldTest{{FieldID: 1}, {FieldID: 2, Scope: 1}, {FieldID: 4, Scope: 2}}
leftComplementary, rightComplementary, intersection = DiffSliceCal(left, right, eqFuncTest)
fmt.Printf("leftComplementary:%v \n, rightComplementary:%v \n, intersection:%v \n-------------- \n", leftComplementary, rightComplementary, intersection)
}
上面的可以通用工具,可以使用自定义类型,eq方法,就可以使用了。
可以返回leftComplementary left集合补集, rightComplementary :right 集合补集,
intersection:left和right的交集(同时返回left和right的元素对比,方便后续处理)
运行结果如下:
=== RUN Test_diffCal
leftComplementary:[]
, rightComplementary:[]
, intersection:[{{1 0} {1 0}}]
--------------
leftComplementary:[{3 2}]
, rightComplementary:[{4 2}]
, intersection:[{{1 1} {1 0}} {{2 1} {2 1}}]
--------------
--- PASS: Test_diffCal (0.00s)
PASS
计算两个map的交集,补集
计算两个map 相同key的交集,补集
import "reflect"
type PairMap struct {
left map[interface{}]interface{}
right map[interface{}]interface{}
}
type EqFunc func(leftItem interface{}, rightItem interface{}) bool
func DiffMapCal(left interface{}, right interface{}, keyEqFunc EqFunc) (leftComplementary, rightComplementary interface{}, intersection PairMap) {
checkMapType(left, "left")
checkMapType(right, "right")
leftMap := reflect.ValueOf(left)
rightMap := reflect.ValueOf(right)
itLeft := leftMap.MapRange()
itRight := rightMap.MapRange()
eqLeftMap := map[interface{}]int{}
eqRightMap := map[interface{}]int{}
intersection.left = map[interface{}]interface{}{}
intersection.right = map[interface{}]interface{}{}
for itLeft.Next() {
leftKey := itLeft.Key().Interface()
for itRight.Next() {
rightKey := itRight.Key().Interface()
if keyEqFunc(leftKey, rightKey) {
eqLeftMap[leftKey] = 1
eqRightMap[rightKey] = 1
intersection.left[leftKey] = itLeft.Value().Interface()
intersection.right[rightKey] = itRight.Value().Interface()
}
}
itRight = rightMap.MapRange()
}
leftComplementary = calNotEqualMap(leftMap, eqLeftMap)
rightComplementary = calNotEqualMap(rightMap, eqRightMap)
return
}
func calNotEqualMap(m reflect.Value, eqKeyMap map[interface{}]int) (ret interface{}) {
retMap := make(map[interface{}]interface{}, 0)
it := m.MapRange()
for it.Next() {
itemKey := it.Key().Interface()
itemValue := it.Value().Interface()
if _, exists := eqKeyMap[itemKey]; !exists {
retMap[itemKey] = itemValue
}
}
ret = retMap
return
}
测试用例:
import (
"fmt"
"testing"
)
type FieldTest struct {
FieldID int64 `json:"field_id"`
Scope int `json:"scope"`
}
func Test_DiffMapCal(t *testing.T) {
left := map[int64]FieldTest{20001: {FieldID: 1}}
right := map[int64]FieldTest{20001: {FieldID: 1}}
eqFuncTest := func(leftItem interface{}, rightItem interface{}) bool {
l := leftItem.(int64)
r := rightItem.(int64)
return l == r
}
leftComplementary, rightComplementary, intersection := DiffMapCal(left, right, eqFuncTest)
fmt.Printf("leftComplementary:%v \n, rightComplementary:%v \n, intersection:%v \n-------------- \n", leftComplementary, rightComplementary, intersection)
left = map[int64]FieldTest{20001: {FieldID: 1, Scope: 1}, 20002: {FieldID: 2, Scope: 1}, 20003: {FieldID: 3, Scope: 2}}
right = map[int64]FieldTest{20001: {FieldID: 1}, 20002: {FieldID: 2, Scope: 1}, 20004: {FieldID: 4, Scope: 2}}
leftComplementary, rightComplementary, intersection = DiffMapCal(left, right, eqFuncTest)
fmt.Printf("leftComplementary:%v \n, rightComplementary:%v \n, intersection:%v \n-------------- \n", leftComplementary, rightComplementary, intersection)
}
运行结果如下:
=== RUN Test_DiffMapCal
leftComplementary:map[]
, rightComplementary:map[]
, intersection:{map[20001:{1 0}] map[20001:{1 0}]}
--------------
leftComplementary:map[20003:{3 2}]
, rightComplementary:map[20004:{4 2}]
, intersection:{map[20001:{1 1} 20002:{2 1}] map[20001:{1 0} 20002:{2 1}]}
--------------
--- PASS: Test_DiffMapCal (0.00s)
PASS
进一步针对for循环的优化可以修改为:
使用map替换原来的两层for循环
import "reflect"
type PairMap struct {
left map[interface{}]interface{}
right map[interface{}]interface{}
}
func DiffMapCal(left interface{}, right interface{}) (leftComplementary, rightComplementary interface{}, intersection PairMap) {
checkMapType(left, "left")
checkMapType(right, "right")
leftMap := reflect.ValueOf(left)
rightMap := reflect.ValueOf(right)
itLeft := leftMap.MapRange()
itRight := rightMap.MapRange()
eqMap := map[interface{}]int{}
intersection.left = map[interface{}]interface{}{}
intersection.right = map[interface{}]interface{}{}
rightKeyValueMap := map[interface{}]interface{}{}
for itRight.Next() {
rightKey := itRight.Key().Interface()
rightKeyValueMap[rightKey] = itRight.Value().Interface()
}
for itLeft.Next() {
key := itLeft.Key().Interface()
var rightValue interface{}
var ok bool
if rightValue, ok = rightKeyValueMap[key]; !ok {
continue
}
eqMap[key] = 1
intersection.left[key] = itLeft.Value().Interface()
intersection.right[key] = rightValue
}
leftComplementary = calNotEqualMap(leftMap, eqMap)
rightComplementary = calNotEqualMap(rightMap, eqMap)
return
}
测试结果:
func Test_DiffMapCal(t *testing.T) {
left := map[int64]FieldTest{20001: {FieldID: 1}}
right := map[int64]FieldTest{20001: {FieldID: 1}}
leftComplementary, rightComplementary, intersection := DiffMapCal(left, right)
fmt.Printf("leftComplementary:%v \n, rightComplementary:%v \n, intersection:%v \n-------------- \n", leftComplementary, rightComplementary, intersection)
left = map[int64]FieldTest{20001: {FieldID: 1, Scope: 1}, 20002: {FieldID: 2, Scope: 1}, 20003: {FieldID: 3, Scope: 2}}
right = map[int64]FieldTest{20001: {FieldID: 1}, 20002: {FieldID: 2, Scope: 1}, 20004: {FieldID: 4, Scope: 2}}
leftComplementary, rightComplementary, intersection = DiffMapCal(left, right)
fmt.Printf("leftComplementary:%v \n, rightComplementary:%v \n, intersection:%v \n-------------- \n", leftComplementary, rightComplementary, intersection)
}
计算结果:
=== RUN Test_DiffMapCal
leftComplementary:map[]
, rightComplementary:map[]
, intersection:{map[20001:{1 0}] map[20001:{1 0}]}
--------------
leftComplementary:map[20003:{3 2}]
, rightComplementary:map[20004:{4 2}]
, intersection:{map[20001:{1 1} 20002:{2 1}] map[20001:{1 0} 20002:{2 1}]}
--------------
--- PASS: Test_DiffMapCal (0.00s)
PASS
其他:
开源set包