mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
feat: add Diff feature to gmap (#2774)
This commit is contained in:
@ -13,6 +13,7 @@ import (
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"github.com/gogf/gf/v2/internal/rwmutex"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// AnyAnyMap wraps map type `map[interface{}]interface{}` and provides more map features.
|
||||
@ -535,3 +536,28 @@ func (m *AnyAnyMap) IsSubOf(other *AnyAnyMap) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Diff compares current map `m` with map `other` and returns their different keys.
|
||||
// The returned `addedKeys` are the keys that are in map `m` but not in map `other`.
|
||||
// The returned `removedKeys` are the keys that are in map `other` but not in map `m`.
|
||||
// The returned `updatedKeys` are the keys that are both in map `m` and `other` but their values and not equal (`!=`).
|
||||
func (m *AnyAnyMap) Diff(other *AnyAnyMap) (addedKeys, removedKeys, updatedKeys []interface{}) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
|
||||
for key := range m.data {
|
||||
if _, ok := other.data[key]; !ok {
|
||||
removedKeys = append(removedKeys, key)
|
||||
} else if !reflect.DeepEqual(m.data[key], other.data[key]) {
|
||||
updatedKeys = append(updatedKeys, key)
|
||||
}
|
||||
}
|
||||
for key := range other.data {
|
||||
if _, ok := m.data[key]; !ok {
|
||||
addedKeys = append(addedKeys, key)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ import (
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"github.com/gogf/gf/v2/internal/rwmutex"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// IntAnyMap implements map[int]interface{} with RWMutex that has switch.
|
||||
@ -536,3 +537,28 @@ func (m *IntAnyMap) IsSubOf(other *IntAnyMap) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Diff compares current map `m` with map `other` and returns their different keys.
|
||||
// The returned `addedKeys` are the keys that are in map `m` but not in map `other`.
|
||||
// The returned `removedKeys` are the keys that are in map `other` but not in map `m`.
|
||||
// The returned `updatedKeys` are the keys that are both in map `m` and `other` but their values and not equal (`!=`).
|
||||
func (m *IntAnyMap) Diff(other *IntAnyMap) (addedKeys, removedKeys, updatedKeys []int) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
|
||||
for key := range m.data {
|
||||
if _, ok := other.data[key]; !ok {
|
||||
removedKeys = append(removedKeys, key)
|
||||
} else if !reflect.DeepEqual(m.data[key], other.data[key]) {
|
||||
updatedKeys = append(updatedKeys, key)
|
||||
}
|
||||
}
|
||||
for key := range other.data {
|
||||
if _, ok := m.data[key]; !ok {
|
||||
addedKeys = append(addedKeys, key)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -506,3 +506,28 @@ func (m *IntIntMap) IsSubOf(other *IntIntMap) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Diff compares current map `m` with map `other` and returns their different keys.
|
||||
// The returned `addedKeys` are the keys that are in map `m` but not in map `other`.
|
||||
// The returned `removedKeys` are the keys that are in map `other` but not in map `m`.
|
||||
// The returned `updatedKeys` are the keys that are both in map `m` and `other` but their values and not equal (`!=`).
|
||||
func (m *IntIntMap) Diff(other *IntIntMap) (addedKeys, removedKeys, updatedKeys []int) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
|
||||
for key := range m.data {
|
||||
if _, ok := other.data[key]; !ok {
|
||||
removedKeys = append(removedKeys, key)
|
||||
} else if m.data[key] != other.data[key] {
|
||||
updatedKeys = append(updatedKeys, key)
|
||||
}
|
||||
}
|
||||
for key := range other.data {
|
||||
if _, ok := m.data[key]; !ok {
|
||||
addedKeys = append(addedKeys, key)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -506,3 +506,28 @@ func (m *IntStrMap) IsSubOf(other *IntStrMap) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Diff compares current map `m` with map `other` and returns their different keys.
|
||||
// The returned `addedKeys` are the keys that are in map `m` but not in map `other`.
|
||||
// The returned `removedKeys` are the keys that are in map `other` but not in map `m`.
|
||||
// The returned `updatedKeys` are the keys that are both in map `m` and `other` but their values and not equal (`!=`).
|
||||
func (m *IntStrMap) Diff(other *IntStrMap) (addedKeys, removedKeys, updatedKeys []int) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
|
||||
for key := range m.data {
|
||||
if _, ok := other.data[key]; !ok {
|
||||
removedKeys = append(removedKeys, key)
|
||||
} else if m.data[key] != other.data[key] {
|
||||
updatedKeys = append(updatedKeys, key)
|
||||
}
|
||||
}
|
||||
for key := range other.data {
|
||||
if _, ok := m.data[key]; !ok {
|
||||
addedKeys = append(addedKeys, key)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ import (
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"github.com/gogf/gf/v2/internal/rwmutex"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// StrAnyMap implements map[string]interface{} with RWMutex that has switch.
|
||||
@ -522,3 +523,28 @@ func (m *StrAnyMap) IsSubOf(other *StrAnyMap) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Diff compares current map `m` with map `other` and returns their different keys.
|
||||
// The returned `addedKeys` are the keys that are in map `m` but not in map `other`.
|
||||
// The returned `removedKeys` are the keys that are in map `other` but not in map `m`.
|
||||
// The returned `updatedKeys` are the keys that are both in map `m` and `other` but their values and not equal (`!=`).
|
||||
func (m *StrAnyMap) Diff(other *StrAnyMap) (addedKeys, removedKeys, updatedKeys []string) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
|
||||
for key := range m.data {
|
||||
if _, ok := other.data[key]; !ok {
|
||||
removedKeys = append(removedKeys, key)
|
||||
} else if !reflect.DeepEqual(m.data[key], other.data[key]) {
|
||||
updatedKeys = append(updatedKeys, key)
|
||||
}
|
||||
}
|
||||
for key := range other.data {
|
||||
if _, ok := m.data[key]; !ok {
|
||||
addedKeys = append(addedKeys, key)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -510,3 +510,28 @@ func (m *StrIntMap) IsSubOf(other *StrIntMap) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Diff compares current map `m` with map `other` and returns their different keys.
|
||||
// The returned `addedKeys` are the keys that are in map `m` but not in map `other`.
|
||||
// The returned `removedKeys` are the keys that are in map `other` but not in map `m`.
|
||||
// The returned `updatedKeys` are the keys that are both in map `m` and `other` but their values and not equal (`!=`).
|
||||
func (m *StrIntMap) Diff(other *StrIntMap) (addedKeys, removedKeys, updatedKeys []string) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
|
||||
for key := range m.data {
|
||||
if _, ok := other.data[key]; !ok {
|
||||
removedKeys = append(removedKeys, key)
|
||||
} else if m.data[key] != other.data[key] {
|
||||
updatedKeys = append(updatedKeys, key)
|
||||
}
|
||||
}
|
||||
for key := range other.data {
|
||||
if _, ok := m.data[key]; !ok {
|
||||
addedKeys = append(addedKeys, key)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -499,3 +499,28 @@ func (m *StrStrMap) IsSubOf(other *StrStrMap) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Diff compares current map `m` with map `other` and returns their different keys.
|
||||
// The returned `addedKeys` are the keys that are in map `m` but not in map `other`.
|
||||
// The returned `removedKeys` are the keys that are in map `other` but not in map `m`.
|
||||
// The returned `updatedKeys` are the keys that are both in map `m` and `other` but their values and not equal (`!=`).
|
||||
func (m *StrStrMap) Diff(other *StrStrMap) (addedKeys, removedKeys, updatedKeys []string) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
|
||||
for key := range m.data {
|
||||
if _, ok := other.data[key]; !ok {
|
||||
removedKeys = append(removedKeys, key)
|
||||
} else if m.data[key] != other.data[key] {
|
||||
updatedKeys = append(updatedKeys, key)
|
||||
}
|
||||
}
|
||||
for key := range other.data {
|
||||
if _, ok := m.data[key]; !ok {
|
||||
addedKeys = append(addedKeys, key)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -406,3 +406,24 @@ func Test_AnyAnyMap_IsSubOf(t *testing.T) {
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_AnyAnyMap_Diff(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewAnyAnyMapFrom(g.MapAnyAny{
|
||||
"0": "v0",
|
||||
"1": "v1",
|
||||
2: "v2",
|
||||
3: 3,
|
||||
})
|
||||
m2 := gmap.NewAnyAnyMapFrom(g.MapAnyAny{
|
||||
"0": "v0",
|
||||
2: "v2",
|
||||
3: "v3",
|
||||
4: "v4",
|
||||
})
|
||||
addedKeys, removedKeys, updatedKeys := m1.Diff(m2)
|
||||
t.Assert(addedKeys, []interface{}{4})
|
||||
t.Assert(removedKeys, []interface{}{"1"})
|
||||
t.Assert(updatedKeys, []interface{}{3})
|
||||
})
|
||||
}
|
||||
|
||||
@ -390,3 +390,24 @@ func Test_IntAnyMap_IsSubOf(t *testing.T) {
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntAnyMap_Diff(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewIntAnyMapFrom(g.MapIntAny{
|
||||
0: "v0",
|
||||
1: "v1",
|
||||
2: "v2",
|
||||
3: 3,
|
||||
})
|
||||
m2 := gmap.NewIntAnyMapFrom(g.MapIntAny{
|
||||
0: "v0",
|
||||
2: "v2",
|
||||
3: "v3",
|
||||
4: "v4",
|
||||
})
|
||||
addedKeys, removedKeys, updatedKeys := m1.Diff(m2)
|
||||
t.Assert(addedKeys, []int{4})
|
||||
t.Assert(removedKeys, []int{1})
|
||||
t.Assert(updatedKeys, []int{3})
|
||||
})
|
||||
}
|
||||
|
||||
@ -398,3 +398,24 @@ func Test_IntIntMap_IsSubOf(t *testing.T) {
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntIntMap_Diff(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewIntIntMapFrom(g.MapIntInt{
|
||||
0: 0,
|
||||
1: 1,
|
||||
2: 2,
|
||||
3: 3,
|
||||
})
|
||||
m2 := gmap.NewIntIntMapFrom(g.MapIntInt{
|
||||
0: 0,
|
||||
2: 2,
|
||||
3: 31,
|
||||
4: 4,
|
||||
})
|
||||
addedKeys, removedKeys, updatedKeys := m1.Diff(m2)
|
||||
t.Assert(addedKeys, []int{4})
|
||||
t.Assert(removedKeys, []int{1})
|
||||
t.Assert(updatedKeys, []int{3})
|
||||
})
|
||||
}
|
||||
|
||||
@ -462,3 +462,24 @@ func Test_IntStrMap_IsSubOf(t *testing.T) {
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntStrMap_Diff(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewIntStrMapFrom(g.MapIntStr{
|
||||
0: "0",
|
||||
1: "1",
|
||||
2: "2",
|
||||
3: "3",
|
||||
})
|
||||
m2 := gmap.NewIntStrMapFrom(g.MapIntStr{
|
||||
0: "0",
|
||||
2: "2",
|
||||
3: "31",
|
||||
4: "4",
|
||||
})
|
||||
addedKeys, removedKeys, updatedKeys := m1.Diff(m2)
|
||||
t.Assert(addedKeys, []int{4})
|
||||
t.Assert(removedKeys, []int{1})
|
||||
t.Assert(updatedKeys, []int{3})
|
||||
})
|
||||
}
|
||||
|
||||
@ -396,3 +396,24 @@ func Test_StrAnyMap_IsSubOf(t *testing.T) {
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrAnyMap_Diff(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewStrAnyMapFrom(g.MapStrAny{
|
||||
"0": "v0",
|
||||
"1": "v1",
|
||||
"2": "v2",
|
||||
"3": 3,
|
||||
})
|
||||
m2 := gmap.NewStrAnyMapFrom(g.MapStrAny{
|
||||
"0": "v0",
|
||||
"2": "v2",
|
||||
"3": "v3",
|
||||
"4": "v4",
|
||||
})
|
||||
addedKeys, removedKeys, updatedKeys := m1.Diff(m2)
|
||||
t.Assert(addedKeys, []string{"4"})
|
||||
t.Assert(removedKeys, []string{"1"})
|
||||
t.Assert(updatedKeys, []string{"3"})
|
||||
})
|
||||
}
|
||||
|
||||
@ -404,3 +404,24 @@ func Test_StrIntMap_IsSubOf(t *testing.T) {
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrIntMap_Diff(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewStrIntMapFrom(g.MapStrInt{
|
||||
"0": 0,
|
||||
"1": 1,
|
||||
"2": 2,
|
||||
"3": 3,
|
||||
})
|
||||
m2 := gmap.NewStrIntMapFrom(g.MapStrInt{
|
||||
"0": 0,
|
||||
"2": 2,
|
||||
"3": 31,
|
||||
"4": 4,
|
||||
})
|
||||
addedKeys, removedKeys, updatedKeys := m1.Diff(m2)
|
||||
t.Assert(addedKeys, []string{"4"})
|
||||
t.Assert(removedKeys, []string{"1"})
|
||||
t.Assert(updatedKeys, []string{"3"})
|
||||
})
|
||||
}
|
||||
|
||||
@ -403,3 +403,24 @@ func Test_StrStrMap_IsSubOf(t *testing.T) {
|
||||
t.Assert(m2.IsSubOf(m2), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrStrMap_Diff(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m1 := gmap.NewStrStrMapFrom(g.MapStrStr{
|
||||
"0": "0",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
})
|
||||
m2 := gmap.NewStrStrMapFrom(g.MapStrStr{
|
||||
"0": "0",
|
||||
"2": "2",
|
||||
"3": "31",
|
||||
"4": "4",
|
||||
})
|
||||
addedKeys, removedKeys, updatedKeys := m1.Diff(m2)
|
||||
t.Assert(addedKeys, []string{"4"})
|
||||
t.Assert(removedKeys, []string{"1"})
|
||||
t.Assert(updatedKeys, []string{"3"})
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user