github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/structure/maps/treebidimap/treebidimap.go (about) 1 // Package treebidimap implements a bidirectional map backed by two red-black tree. 2 // 3 // This structure guarantees that the map will be in both ascending key and value order. 4 // 5 // Other than key and value ordering, the goal with this structure is to avoid duplication of elements, which can be significant if contained elements are large. 6 // 7 // A bidirectional map, or hash bag, is an associative data structure in which the (key,value) pairs form a one-to-one correspondence. 8 // Thus the binary relation is functional in each direction: value can also act as a key to key. 9 // A pair (a,b) thus provides a unique coupling between 'a' and 'b' so that 'b' can be found when 'a' is used as a key and 'a' can be found when 'b' is used as a key. 10 // 11 // Structure is not thread safe. 12 // 13 // Reference: https://en.wikipedia.org/wiki/Bidirectional_map 14 package treebidimap 15 16 import ( 17 "encoding/json" 18 "fmt" 19 "strings" 20 21 banytostring "github.com/songzhibin97/go-baseutils/base/banytostring" 22 "github.com/songzhibin97/go-baseutils/base/bcomparator" 23 "github.com/songzhibin97/go-baseutils/structure/maps" 24 "github.com/songzhibin97/go-baseutils/structure/trees/redblacktree" 25 ) 26 27 // Assert Map implementation 28 var _ maps.BidiMap[int, int] = (*Map[int, int])(nil) 29 30 // Map holds the elements in two red-black trees. 31 type Map[K, V any] struct { 32 forwardMap redblacktree.Tree[K, V] 33 inverseMap redblacktree.Tree[V, K] 34 keyComparator bcomparator.Comparator[K] 35 valueComparator bcomparator.Comparator[V] 36 zeroK K 37 zeroV V 38 } 39 40 // NewWith instantiates a bidirectional map. 41 func NewWith[K, V any](keyComparator bcomparator.Comparator[K], valueComparator bcomparator.Comparator[V]) *Map[K, V] { 42 return &Map[K, V]{ 43 forwardMap: *redblacktree.NewWith[K, V](keyComparator), 44 inverseMap: *redblacktree.NewWith[V, K](valueComparator), 45 keyComparator: keyComparator, 46 valueComparator: valueComparator, 47 } 48 } 49 50 // NewWithIntComparators instantiates a bidirectional map with the IntComparator for key and value, i.e. keys and values are of type int. 51 func NewWithIntComparators() *Map[int, int] { 52 return NewWith(bcomparator.IntComparator(), bcomparator.IntComparator()) 53 } 54 55 // NewWithStringComparators instantiates a bidirectional map with the StringComparator for key and value, i.e. keys and values are of type string. 56 func NewWithStringComparators() *Map[string, string] { 57 return NewWith(bcomparator.StringComparator(), bcomparator.StringComparator()) 58 } 59 60 // Put inserts element into the map. 61 func (m *Map[K, V]) Put(key K, value V) { 62 if d, ok := m.forwardMap.Get(key); ok { 63 m.inverseMap.Remove(d) 64 } 65 if d, ok := m.inverseMap.Get(value); ok { 66 m.forwardMap.Remove(d) 67 } 68 m.forwardMap.Put(key, value) 69 m.inverseMap.Put(value, key) 70 } 71 72 // Get searches the element in the map by key and returns its value or nil if key is not found in map. 73 // Second return parameter is true if key was found, otherwise false. 74 func (m *Map[K, V]) Get(key K) (value V, found bool) { 75 if d, ok := m.forwardMap.Get(key); ok { 76 return d, true 77 } 78 return m.zeroV, false 79 } 80 81 // GetKey searches the element in the map by value and returns its key or nil if value is not found in map. 82 // Second return parameter is true if value was found, otherwise false. 83 func (m *Map[K, V]) GetKey(value V) (key K, found bool) { 84 if d, ok := m.inverseMap.Get(value); ok { 85 return d, true 86 } 87 return m.zeroK, false 88 } 89 90 // Remove removes the element from the map by key. 91 func (m *Map[K, V]) Remove(key K) { 92 if d, found := m.forwardMap.Get(key); found { 93 m.forwardMap.Remove(key) 94 m.inverseMap.Remove(d) 95 } 96 } 97 98 // Empty returns true if map does not contain any elements 99 func (m *Map[K, V]) Empty() bool { 100 return m.Size() == 0 101 } 102 103 // Size returns number of elements in the map. 104 func (m *Map[K, V]) Size() int { 105 return m.forwardMap.Size() 106 } 107 108 // Keys returns all keys (ordered). 109 func (m *Map[K, V]) Keys() []K { 110 return m.forwardMap.Keys() 111 } 112 113 // Values returns all values (ordered). 114 func (m *Map[K, V]) Values() []V { 115 return m.inverseMap.Keys() 116 } 117 118 // Clear removes all elements from the map. 119 func (m *Map[K, V]) Clear() { 120 m.forwardMap.Clear() 121 m.inverseMap.Clear() 122 } 123 124 // String returns a string representation of container 125 func (m *Map[K, V]) String() string { 126 bf := strings.Builder{} 127 bf.WriteString("TreeBidiMap\nmap[") 128 it := m.Iterator() 129 for it.Next() { 130 bf.WriteString(fmt.Sprintf("(%v:%v) ", it.Key(), it.Value())) 131 } 132 bf.WriteString("]") 133 return bf.String() 134 } 135 136 // UnmarshalJSON @implements json.Unmarshaler 137 func (m *Map[K, V]) UnmarshalJSON(bytes []byte) error { 138 elements := make(map[string]interface{}) 139 err := json.Unmarshal(bytes, &elements) 140 if err == nil { 141 m.Clear() 142 for key, value := range elements { 143 var nk K 144 err = m.keyComparator.Unmarshal([]byte(key), &nk) 145 if err != nil { 146 return err 147 } 148 var nv V 149 err = m.valueComparator.Unmarshal([]byte(banytostring.ToString(value)), &nv) 150 if err != nil { 151 return err 152 } 153 m.Put(nk, nv) 154 } 155 } 156 return err 157 } 158 159 // MarshalJSON @implements json.Marshaler 160 func (m *Map[K, V]) MarshalJSON() ([]byte, error) { 161 elements := make(map[string]string) 162 it := m.Iterator() 163 for it.Next() { 164 k, err := m.keyComparator.Marshal(it.Key()) 165 if err != nil { 166 return nil, err 167 } 168 v, err := m.valueComparator.Marshal(it.Value()) 169 if err != nil { 170 return nil, err 171 } 172 elements[string(k)] = string(v) 173 } 174 return json.Marshal(&elements) 175 }