├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── go.mod ├── multimap.go ├── setmultimap ├── example_test.go ├── setmultimap.go └── setmultimap_test.go └── slicemultimap ├── example_test.go ├── slicemultimap.go └── slicemultimap_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | coverage.out 2 | /example/example.go 3 | 4 | # OS X 5 | .DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.5 5 | - 1.6 6 | - 1.7 7 | - 1.8 8 | - 1.9 9 | - tip -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Jason Wangsadinata 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![GoDoc](https://godoc.org/github.com/jwangsadinata/go-multimap?status.svg)](https://godoc.org/github.com/jwangsadinata/go-multimap) [![Build Status](https://travis-ci.org/jwangsadinata/go-multimap.svg)](https://travis-ci.org/jwangsadinata/go-multimap) [![Go Report Card](https://goreportcard.com/badge/github.com/jwangsadinata/go-multimap)](https://goreportcard.com/report/github.com/jwangsadinata/go-multimap) [![Coverage Status](https://coveralls.io/repos/github/jwangsadinata/go-multimap/badge.svg?branch=master&service=github)](https://coveralls.io/github/jwangsadinata/go-multimap?branch=master&service=github) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/jwangsadinata/go-multimap/blob/master/LICENSE) 2 | 3 | # Go-Multimap 4 | 5 | This is the missing `multimap` collection for the [Go](https://www.golang.org/project/) language (also a simple practice in creating a proper library/package). 6 | 7 | A multimap (sometimes also multihash or multidict) is a generalization of a map 8 | or associative array abstract data type in which more than one value may be 9 | associated with and returned for a given key. 10 | 11 | Some use cases and examples for this data type includes: 12 | - The index of a book may report any number of references for a given index term, 13 | and thus may be coded as a multimap from index terms to any number of reference locations or pages. 14 | - Address location, such as ZIP code, that maps to any number of people living in that area. 15 | 16 | There are two different multimap implementations, `slicemultimap` and `setmultimap`, which has slices and sets 17 | as the map values respectively. `slicemultimap` is useful when duplicate key/value pairs is allowed and 18 | insertion ordering is important. On the other hand, `setmultimap` is suitable when duplicates of key/value 19 | pairs are not allowed. 20 | 21 | This package was heavily inspired by the Google Guava interface of MultiMap and 22 | written in the style of the [container](https://golang.org/pkg/container/) package. 23 | 24 | 25 | References: 26 | [Wikipedia](https://en.wikipedia.org/wiki/Multimap), 27 | [Guava](https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Multimap.html) 28 | 29 | ## Installation ## 30 | 31 | Install the package via the following: 32 | 33 | go get -u github.com/jwangsadinata/go-multimap 34 | 35 | ## Usage ## 36 | 37 | The go-multimap package can be used similarly to the following: 38 | ```go 39 | // example/example.go 40 | package main 41 | 42 | import ( 43 | "fmt" 44 | 45 | "github.com/jwangsadinata/go-multimap/slicemultimap" 46 | ) 47 | 48 | func main() { 49 | usPresidents := []struct { 50 | firstName string 51 | middleName string 52 | lastName string 53 | termStart int 54 | termEnd int 55 | }{ 56 | {"George", "", "Washington", 1789, 1797}, 57 | {"John", "", "Adams", 1797, 1801}, 58 | {"Thomas", "", "Jefferson", 1801, 1809}, 59 | {"James", "", "Madison", 1809, 1817}, 60 | {"James", "", "Monroe", 1817, 1825}, 61 | {"John", "Quincy", "Adams", 1825, 1829}, 62 | {"John", "", "Tyler", 1841, 1845}, 63 | {"James", "", "Polk", 1845, 1849}, 64 | {"Grover", "", "Cleveland", 1885, 1889}, 65 | {"Benjamin", "", "Harrison", 1889, 1893}, 66 | {"Grover", "", "Cleveland", 1893, 1897}, 67 | {"George", "Herbert Walker", "Bush", 1989, 1993}, 68 | {"George", "Walker", "Bush", 2001, 2009}, 69 | {"Barack", "Hussein", "Obama", 2009, 2017}, 70 | } 71 | 72 | m := slicemultimap.New() 73 | 74 | for _, president := range usPresidents { 75 | m.Put(president.firstName, president.lastName) 76 | } 77 | 78 | for _, firstName := range m.KeySet() { 79 | lastNames, _ := m.Get(firstName) 80 | fmt.Printf("%v: %v\n", firstName, lastNames) 81 | } 82 | } 83 | ``` 84 | 85 | Example output: 86 | ```sh 87 | $ go run example.go 88 | George: [Washington Bush Bush] 89 | John: [Adams Adams Tyler] 90 | Thomas: [Jefferson] 91 | James: [Madison Monroe Polk] 92 | Grover: [Cleveland Cleveland] 93 | Benjamin: [Harrison] 94 | Barack: [Obama] 95 | ``` 96 | 97 | ## Benchmarks ## 98 | To see the benchmark, run the following on each of the sub-packages: 99 | 100 | `go test -run=NO_TEST -bench . -benchmem -benchtime 1s ./...` 101 | 102 |

103 |

104 | 105 | 106 | Please see [the GoDoc API page](http://godoc.org/github.com/jwangsadinata/go-multimap) for a 107 | full API listing. For more examples, please consult `example_test.go` file located in each subpackages. 108 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/jwangsadinata/go-multimap 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /multimap.go: -------------------------------------------------------------------------------- 1 | // Package multimap provides an abstract MultiMap interface. 2 | // 3 | // Multimap is a collection that maps keys to values, similar to map. 4 | // However, each key may be associated with multiple values. 5 | // 6 | // You can visualize the contents of a multimap either as a map from keys to nonempty collections of values: 7 | // - a --> 1, 2 8 | // - b --> 3 9 | // ... or a single "flattened" collection of key-value pairs. 10 | // - a --> 1 11 | // - a --> 2 12 | // - b --> 3 13 | // 14 | // Similar to a map, operations associated with this data type allow: 15 | // - the addition of a pair to the collection 16 | // - the removal of a pair from the collection 17 | // - the lookup of a value associated with a particular key 18 | // - the lookup whether a key, value or key/value pair exists in this data type. 19 | package multimap 20 | 21 | // Entry represents a key/value pair inside a multimap. 22 | type Entry struct { 23 | Key interface{} 24 | Value interface{} 25 | } 26 | 27 | // MultiMap interface that all multimaps implement. 28 | type MultiMap interface { 29 | Get(key interface{}) (value []interface{}, found bool) 30 | 31 | Put(key interface{}, value interface{}) 32 | PutAll(key interface{}, value []interface{}) 33 | 34 | Remove(key interface{}, value interface{}) 35 | RemoveAll(key interface{}) 36 | 37 | Contains(key interface{}, value interface{}) bool 38 | ContainsKey(key interface{}) bool 39 | ContainsValue(value interface{}) bool 40 | 41 | Entries() []Entry 42 | Keys() []interface{} 43 | KeySet() []interface{} 44 | Values() []interface{} 45 | 46 | Clear() 47 | Empty() bool 48 | Size() int 49 | } 50 | -------------------------------------------------------------------------------- /setmultimap/example_test.go: -------------------------------------------------------------------------------- 1 | package setmultimap_test 2 | 3 | import ( 4 | "fmt" 5 | "sort" 6 | "strings" 7 | 8 | "github.com/jwangsadinata/go-multimap/setmultimap" 9 | ) 10 | 11 | // The following examples is to demonstrate basic usage of MultiMap. 12 | func ExampleMultiMap_Clear() { 13 | // Create a new multimap 14 | m := setmultimap.New() // empty 15 | 16 | // Put some contents to the multimap. 17 | m.Put(1, "x") // 1->x 18 | m.Put(2, "b") // 1->x, 2->b 19 | m.Put(1, "a") // 1->a, 1->x, 2->b 20 | 21 | // Clear the current map. 22 | m.Clear() // empty 23 | 24 | // Verify that it is empty. 25 | fmt.Printf("%v\n", m.Empty()) 26 | fmt.Printf("%v\n", m.Size()) 27 | 28 | // Output: 29 | // true 30 | // 0 31 | } 32 | 33 | func ExampleMultiMap_Contains() { 34 | // Create a new multimap 35 | m := setmultimap.New() // empty 36 | 37 | // Put some contents to the multimap. 38 | m.Put(1, "x") // 1->x 39 | m.Put(2, "b") // 1->x, 2->b 40 | m.Put(1, "a") // 1->a, 1->x, 2->b 41 | 42 | // Check whether the multimap contains a certain key/value pair. 43 | found := m.Contains(1, "a") // true 44 | fmt.Printf("%v\n", found) 45 | 46 | found = m.Contains(1, "b") // false 47 | fmt.Printf("%v\n", found) 48 | 49 | found = m.Contains(2, "b") // true 50 | fmt.Printf("%v\n", found) 51 | 52 | // Output: 53 | // true 54 | // false 55 | // true 56 | } 57 | 58 | func ExampleMultiMap_ContainsKey() { 59 | // Create a new multimap 60 | m := setmultimap.New() // empty 61 | 62 | // Put some contents to the multimap. 63 | m.Put(1, "x") // 1->x 64 | m.Put(2, "b") // 1->x, 2->b 65 | m.Put(1, "a") // 1->a, 1->x, 2->b 66 | 67 | // Check whether the multimap contains a certain key. 68 | found := m.ContainsKey(1) // true 69 | fmt.Printf("%v\n", found) 70 | 71 | found = m.ContainsKey(2) // true 72 | fmt.Printf("%v\n", found) 73 | 74 | found = m.ContainsKey(3) // true 75 | fmt.Printf("%v\n", found) 76 | 77 | // Output: 78 | // true 79 | // true 80 | // false 81 | } 82 | 83 | func ExampleMultiMap_ContainsValue() { 84 | // Create a new multimap 85 | m := setmultimap.New() // empty 86 | 87 | // Put some contents to the multimap. 88 | m.Put(1, "x") // 1->x 89 | m.Put(2, "b") // 1->x, 2->b 90 | m.Put(1, "a") // 1->a, 1->x, 2->b 91 | 92 | // Check whether the multimap contains a certain value. 93 | found := m.ContainsValue("a") // true 94 | fmt.Printf("%v\n", found) 95 | 96 | found = m.ContainsValue("b") // true 97 | fmt.Printf("%v\n", found) 98 | 99 | found = m.ContainsValue("c") // true 100 | fmt.Printf("%v\n", found) 101 | 102 | // Output: 103 | // true 104 | // true 105 | // false 106 | } 107 | 108 | func ExampleMultiMap_Get() { 109 | // Create a new multimap 110 | m := setmultimap.New() // empty 111 | 112 | // Put some contents to the multimap. 113 | m.Put(1, "x") // 1->x 114 | m.Put(2, "b") // 1->x, 2->b 115 | m.Put(1, "a") // 1->a, 1->x, 2->b 116 | 117 | // Retrieve values from the map. 118 | value, found := m.Get(3) // nil, false 119 | fmt.Printf("%v, %v\n", value, found) 120 | 121 | value, found = m.Get(2) // {b}, true 122 | fmt.Printf("%v, %v\n", value, found) 123 | 124 | value, found = m.Get(1) // {a, x}, true (random order) 125 | 126 | // Workaround for test output consistency: 127 | tmp := make([]string, len(value)) 128 | count := 0 129 | for _, s := range value { 130 | tmp[count] = s.(string) 131 | count++ 132 | } 133 | sort.Strings(tmp) 134 | fmt.Printf("%v, %v\n", tmp, found) 135 | 136 | // Output: 137 | // [], false 138 | // [b], true 139 | // [a x], true 140 | } 141 | 142 | func ExampleMultiMap_Put() { 143 | // Create a new multimap 144 | m := setmultimap.New() // empty 145 | 146 | // Put some contents to the multimap. 147 | m.Put(1, "x") // 1->x 148 | m.Put(2, "b") // 1->x, 2->b 149 | m.Put(1, "a") // 1->a, 1->x, 2->b 150 | 151 | // Verify that the map has the right size. 152 | fmt.Println(m.Size()) 153 | 154 | // Output: 155 | // 3 156 | } 157 | 158 | func ExampleMultiMap_Entries() { 159 | // Create a new multimap 160 | m := setmultimap.New() // empty 161 | 162 | // Put some contents to the multimap. 163 | m.Put(1, "x") // 1->x 164 | m.Put(2, "b") // 1->x, 2->b 165 | m.Put(1, "a") // 1->a, 1->x, 2->b 166 | 167 | // Retrieve all the keys in the map. 168 | entries := m.Entries() // {1,a}, {1,x}, {2,b} (random order) 169 | 170 | // Workaround for test output consistency. 171 | tmp := make([]struct { 172 | Key int 173 | Value string 174 | }, len(entries)) 175 | count := 0 176 | for _, e := range entries { 177 | tmp[count] = struct { 178 | Key int 179 | Value string 180 | }{e.Key.(int), e.Value.(string)} 181 | count++ 182 | } 183 | sort.Sort(byKeyThenValue(tmp)) 184 | fmt.Printf("%v\n", tmp) 185 | 186 | // Output: 187 | // [{1 a} {1 x} {2 b}] 188 | } 189 | 190 | func ExampleMultiMap_Keys() { 191 | // Create a new multimap 192 | m := setmultimap.New() // empty 193 | 194 | // Put some contents to the multimap. 195 | m.Put(1, "x") // 1->x 196 | m.Put(2, "b") // 1->x, 2->b 197 | m.Put(1, "a") // 1->a, 1->x, 2->b 198 | 199 | // Retrieve all the keys in the multimap. 200 | keys := m.Keys() // 1, 1, 2 (random order) 201 | 202 | // Workaround for test output consistency. 203 | tmp := make([]int, len(keys)) 204 | count := 0 205 | for _, key := range keys { 206 | tmp[count] = key.(int) 207 | count++ 208 | } 209 | sort.Ints(tmp) 210 | fmt.Printf("%v\n", tmp) 211 | 212 | // Output: 213 | // [1 1 2] 214 | } 215 | 216 | func ExampleMultiMap_KeySet() { 217 | // Create a new multimap 218 | m := setmultimap.New() // empty 219 | 220 | // Put some contents to the multimap. 221 | m.Put(1, "x") // 1->x 222 | m.Put(2, "b") // 1->x, 2->b 223 | m.Put(1, "a") // 1->a, 1->x, 2->b 224 | 225 | // Retrieve all the distinct keys in the multimap. 226 | keys := m.KeySet() // 1, 2 (random order) 227 | 228 | // Workaround for test output consistency. 229 | tmp := make([]int, len(keys)) 230 | count := 0 231 | for _, key := range keys { 232 | tmp[count] = key.(int) 233 | count++ 234 | } 235 | sort.Ints(tmp) 236 | fmt.Printf("%v\n", tmp) 237 | 238 | // Output: 239 | // [1 2] 240 | } 241 | 242 | func ExampleMultiMap_Values() { 243 | // Create a new multimap 244 | m := setmultimap.New() // empty 245 | 246 | // Put some contents to the multimap. 247 | m.Put(1, "x") // 1->x 248 | m.Put(2, "b") // 1->x, 2->b 249 | m.Put(1, "a") // 1->a, 1->x, 2->b 250 | 251 | // Retrieve all the keys in the map. 252 | values := m.Values() // a, b, x (random order) 253 | 254 | // Workaround for test output consistency. 255 | tmp := make([]string, len(values)) 256 | count := 0 257 | for _, value := range values { 258 | tmp[count] = value.(string) 259 | count++ 260 | } 261 | sort.Strings(tmp) 262 | fmt.Printf("%v\n", tmp) 263 | 264 | // Output: 265 | // [a b x] 266 | } 267 | 268 | func ExampleMultiMap_Remove() { 269 | // Create a new multimap 270 | m := setmultimap.New() // empty 271 | 272 | // Put some contents to the multimap. 273 | m.Put(1, "x") // 1->x 274 | m.Put(2, "b") // 1->x, 2->b 275 | m.Put(1, "a") // 1->a, 1->x, 2->b 276 | 277 | // Remove a key/value pair from the multimap. 278 | m.Remove(2, "b") 279 | 280 | // Verify that the map has less number of key/value pair. 281 | fmt.Println(m.Size()) // 2 282 | 283 | // Also, verify that there are no more (2, "b") key/value pair. 284 | value, found := m.Get(2) 285 | fmt.Printf("%v, %v", value, found) // nil, false 286 | 287 | // Output: 288 | // 2 289 | // [], false 290 | } 291 | 292 | func ExampleMultiMap_RemoveAll() { 293 | // Create a new multimap 294 | m := setmultimap.New() // empty 295 | 296 | // Put some contents to the multimap. 297 | m.Put(1, "x") // 1->x 298 | m.Put(2, "b") // 1->x, 2->b 299 | m.Put(1, "a") // 1->a, 1->x, 2->b 300 | 301 | // Remove a key/value pair from the multimap. 302 | m.RemoveAll(1) 303 | 304 | // Verify that the map has less number of key/value pair. 305 | fmt.Println(m.Size()) // 1 306 | 307 | // Also, verify that there are no more values with key 1. 308 | value, found := m.Get(1) 309 | fmt.Printf("%v, %v", value, found) // nil, false 310 | 311 | // Output: 312 | // 1 313 | // [], false 314 | } 315 | 316 | // Helper for sorting entries. 317 | type byKeyThenValue []struct { 318 | Key int 319 | Value string 320 | } 321 | 322 | func (a byKeyThenValue) Len() int { return len(a) } 323 | func (a byKeyThenValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 324 | func (a byKeyThenValue) Less(i, j int) bool { 325 | if a[i].Key < a[j].Key { 326 | return true 327 | } else if a[i].Key > a[j].Key { 328 | return false 329 | } else { 330 | return strings.Compare(a[i].Value, a[j].Value) < 0 331 | } 332 | } 333 | -------------------------------------------------------------------------------- /setmultimap/setmultimap.go: -------------------------------------------------------------------------------- 1 | // Package setmultimap implements a multimap backed by a set. 2 | // 3 | // A setmultimap cannot hold duplicate key-value pairs. 4 | // Adding a key-value pair that's already in the multimap has no effect. 5 | // 6 | // Elements are unordered in the map. 7 | // 8 | // Structure is not thread safe. 9 | // 10 | package setmultimap 11 | 12 | import multimap "github.com/jwangsadinata/go-multimap" 13 | 14 | var exists = struct{}{} 15 | 16 | // Set represents a set object 17 | type Set map[interface{}]struct{} 18 | 19 | // MultiMap holds the elements in go's native map. 20 | type MultiMap struct { 21 | m map[interface{}]Set 22 | } 23 | 24 | // New instantiates a new multimap. 25 | func New() *MultiMap { 26 | return &MultiMap{m: make(map[interface{}]Set)} 27 | } 28 | 29 | // Get searches the element in the multimap by key. 30 | // It returns its value or nil if key is not found in multimap. 31 | // Second return parameter is true if key was found, otherwise false. 32 | func (m *MultiMap) Get(key interface{}) (values []interface{}, found bool) { 33 | set, found := m.m[key] 34 | values = make([]interface{}, len(set)) 35 | count := 0 36 | for value := range set { 37 | values[count] = value 38 | count++ 39 | } 40 | return 41 | } 42 | 43 | // Put stores a key-value pair in this multimap. 44 | func (m *MultiMap) Put(key interface{}, value interface{}) { 45 | set, found := m.m[key] 46 | if found { 47 | set[value] = exists 48 | } else { 49 | set = make(Set) 50 | set[value] = exists 51 | m.m[key] = set 52 | } 53 | } 54 | 55 | // PutAll stores a key-value pair in this multimap for each of the values, all using the same key key. 56 | func (m *MultiMap) PutAll(key interface{}, values []interface{}) { 57 | for _, value := range values { 58 | m.Put(key, value) 59 | } 60 | } 61 | 62 | // Contains returns true if this multimap contains at least one key-value pair with the key key and the value value. 63 | func (m *MultiMap) Contains(key interface{}, value interface{}) bool { 64 | set, found := m.m[key] 65 | if _, ok := set[value]; ok { 66 | return true && found 67 | } 68 | return false && found 69 | } 70 | 71 | // ContainsKey returns true if this multimap contains at least one key-value pair with the key key. 72 | func (m *MultiMap) ContainsKey(key interface{}) (found bool) { 73 | _, found = m.m[key] 74 | return 75 | } 76 | 77 | // ContainsValue returns true if this multimap contains at least one key-value pair with the value value. 78 | func (m *MultiMap) ContainsValue(value interface{}) bool { 79 | for _, set := range m.m { 80 | if _, ok := set[value]; ok { 81 | return true 82 | } 83 | } 84 | return false 85 | } 86 | 87 | // Remove removes a single key-value pair from this multimap, if such exists. 88 | func (m *MultiMap) Remove(key interface{}, value interface{}) { 89 | set, found := m.m[key] 90 | if found { 91 | delete(set, value) 92 | } 93 | if len(m.m[key]) == 0 { 94 | delete(m.m, key) 95 | } 96 | } 97 | 98 | // RemoveAll removes all values associated with the key from the multimap. 99 | func (m *MultiMap) RemoveAll(key interface{}) { 100 | delete(m.m, key) 101 | } 102 | 103 | // Empty returns true if multimap does not contain any key-value pairs. 104 | func (m *MultiMap) Empty() bool { 105 | return m.Size() == 0 106 | } 107 | 108 | // Size returns number of key-value pairs in the multimap. 109 | func (m *MultiMap) Size() int { 110 | size := 0 111 | for _, set := range m.m { 112 | size += len(set) 113 | } 114 | return size 115 | } 116 | 117 | // Keys returns a view collection containing the key from each key-value pair in this multimap. 118 | // This is done without collapsing duplicates. 119 | func (m *MultiMap) Keys() []interface{} { 120 | keys := make([]interface{}, m.Size()) 121 | count := 0 122 | for key, value := range m.m { 123 | for range value { 124 | keys[count] = key 125 | count++ 126 | } 127 | } 128 | return keys 129 | } 130 | 131 | // KeySet returns all distinct keys contained in this multimap. 132 | func (m *MultiMap) KeySet() []interface{} { 133 | keys := make([]interface{}, len(m.m)) 134 | count := 0 135 | for key := range m.m { 136 | keys[count] = key 137 | count++ 138 | } 139 | return keys 140 | } 141 | 142 | // Values returns all values from each key-value pair contained in this multimap. 143 | // This is done without collapsing duplicates. (size of Values() = MultiMap.Size()). 144 | func (m *MultiMap) Values() []interface{} { 145 | values := make([]interface{}, m.Size()) 146 | count := 0 147 | for _, set := range m.m { 148 | for value := range set { 149 | values[count] = value 150 | count++ 151 | } 152 | } 153 | return values 154 | } 155 | 156 | // Entries view collection of all key-value pairs contained in this multimap. 157 | // The return type is a slice of multimap.Entry instances. 158 | // Retrieving the key and value from the entries result will be as trivial as: 159 | // - var entry = m.Entries()[0] 160 | // - var key = entry.Key 161 | // - var value = entry.Value 162 | func (m *MultiMap) Entries() []multimap.Entry { 163 | entries := make([]multimap.Entry, m.Size()) 164 | count := 0 165 | for key, set := range m.m { 166 | for value := range set { 167 | entries[count] = multimap.Entry{Key: key, Value: value} 168 | count++ 169 | } 170 | } 171 | return entries 172 | } 173 | 174 | // Clear removes all elements from the map. 175 | func (m *MultiMap) Clear() { 176 | m.m = make(map[interface{}]Set) 177 | } 178 | -------------------------------------------------------------------------------- /setmultimap/setmultimap_test.go: -------------------------------------------------------------------------------- 1 | package setmultimap 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | multimap "github.com/jwangsadinata/go-multimap" 8 | ) 9 | 10 | func AssertMultiMapImplementation(t *testing.T) { 11 | var _ multimap.MultiMap = New() 12 | } 13 | 14 | func TestClear(t *testing.T) { 15 | m := New() 16 | m.Put(5, "e") 17 | m.Put(6, "f") 18 | m.Put(7, "g") 19 | m.Put(3, "c") 20 | m.Put(4, "d") 21 | m.Put(1, "x") 22 | m.Put(2, "b") 23 | m.Put(1, "a") 24 | m.Put(1, "a") 25 | 26 | if actualValue := m.Size(); actualValue != 8 { 27 | t.Errorf("expected %v, got %v", 8, actualValue) 28 | } 29 | if actualEmpty := m.Empty(); actualEmpty != false { 30 | t.Errorf("expected an empty multimap: %v, got %v", false, actualEmpty) 31 | } 32 | 33 | m.Clear() 34 | 35 | if actualValue := m.Size(); actualValue != 0 { 36 | t.Errorf("expected %v, got %v", 0, actualValue) 37 | } 38 | if actualEmpty := m.Empty(); actualEmpty != true { 39 | t.Errorf("expected an empty multimap: %v, got %v", true, actualEmpty) 40 | } 41 | } 42 | func TestPut(t *testing.T) { 43 | m := New() 44 | m.Put(5, "e") 45 | m.Put(6, "f") 46 | m.Put(7, "g") 47 | m.Put(3, "c") 48 | m.Put(4, "d") 49 | m.Put(1, "x") 50 | m.Put(2, "b") 51 | m.Put(1, "a") 52 | m.Put(6, "f") 53 | 54 | if actualValue := m.Size(); actualValue != 8 { 55 | t.Errorf("expected %v, got %v", 8, actualValue) 56 | } 57 | if actualValue, expectedValue := m.Keys(), []interface{}{1, 1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) { 58 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 59 | } 60 | if actualValue, expectedValue := m.KeySet(), []interface{}{1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) { 61 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 62 | } 63 | if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "e", "f", "g", "x"}; !sameElements(actualValue, expectedValue) { 64 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 65 | } 66 | 67 | var expectedValue = []multimap.Entry{ 68 | multimap.Entry{Key: 1, Value: "a"}, 69 | multimap.Entry{Key: 1, Value: "x"}, 70 | multimap.Entry{Key: 2, Value: "b"}, 71 | multimap.Entry{Key: 3, Value: "c"}, 72 | multimap.Entry{Key: 4, Value: "d"}, 73 | multimap.Entry{Key: 5, Value: "e"}, 74 | multimap.Entry{Key: 6, Value: "f"}, 75 | multimap.Entry{Key: 7, Value: "g"}, 76 | } 77 | if actualValue := m.Entries(); !sameEntries(actualValue, expectedValue) { 78 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 79 | } 80 | 81 | tests := []struct { 82 | key interface{} 83 | expectedValue []interface{} 84 | expectedFound bool 85 | }{ 86 | {1, []interface{}{"a", "x"}, true}, 87 | {2, []interface{}{"b"}, true}, 88 | {3, []interface{}{"c"}, true}, 89 | {4, []interface{}{"d"}, true}, 90 | {5, []interface{}{"e"}, true}, 91 | {6, []interface{}{"f"}, true}, 92 | {7, []interface{}{"g"}, true}, 93 | {8, nil, false}, 94 | {9, nil, false}, 95 | } 96 | 97 | for i, test := range tests { 98 | actualValue, actualFound := m.Get(test.key) 99 | if !sameElements(actualValue, test.expectedValue) || actualFound != test.expectedFound { 100 | t.Errorf("test %d: expected %v, got: %v ", i+1, test.expectedValue, actualValue) 101 | } 102 | } 103 | } 104 | 105 | func TestPutAll(t *testing.T) { 106 | m := New() 107 | m.Put(3, "c") 108 | m.Put(4, "d") 109 | m.Put(2, "b") 110 | m.PutAll(1, []interface{}{"a", "x", "y"}) 111 | 112 | if actualValue := m.Size(); actualValue != 6 { 113 | t.Errorf("expected %v, got %v", 6, actualValue) 114 | } 115 | if actualValue, expectedValue := m.Keys(), []interface{}{1, 1, 1, 2, 3, 4}; !sameElements(actualValue, expectedValue) { 116 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 117 | } 118 | if actualValue, expectedValue := m.KeySet(), []interface{}{1, 2, 3, 4}; !sameElements(actualValue, expectedValue) { 119 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 120 | } 121 | if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "x", "y"}; !sameElements(actualValue, expectedValue) { 122 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 123 | } 124 | 125 | var expectedValue = []multimap.Entry{ 126 | multimap.Entry{Key: 1, Value: "a"}, 127 | multimap.Entry{Key: 1, Value: "x"}, 128 | multimap.Entry{Key: 1, Value: "y"}, 129 | multimap.Entry{Key: 2, Value: "b"}, 130 | multimap.Entry{Key: 3, Value: "c"}, 131 | multimap.Entry{Key: 4, Value: "d"}, 132 | } 133 | if actualValue := m.Entries(); !sameEntries(actualValue, expectedValue) { 134 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 135 | } 136 | 137 | tests := []struct { 138 | key interface{} 139 | expectedValue []interface{} 140 | expectedFound bool 141 | }{ 142 | {1, []interface{}{"a", "x", "y"}, true}, 143 | {2, []interface{}{"b"}, true}, 144 | {3, []interface{}{"c"}, true}, 145 | {4, []interface{}{"d"}, true}, 146 | {5, nil, false}, 147 | {6, nil, false}, 148 | } 149 | 150 | for i, test := range tests { 151 | // Test for retrievals. 152 | actualValue, actualFound := m.Get(test.key) 153 | if !sameElements(actualValue, test.expectedValue) || actualFound != test.expectedFound { 154 | t.Errorf("test %d: expected %v, got: %v ", i+1, test.expectedValue, actualValue) 155 | } 156 | } 157 | } 158 | 159 | func TestContains(t *testing.T) { 160 | m := New() 161 | m.Put(3, "c") 162 | m.Put(4, "d") 163 | m.Put(2, "b") 164 | m.PutAll(1, []interface{}{"a", "x", "y"}) 165 | 166 | if actualValue, expectedValue := m.Contains(1, "a"), true; actualValue != expectedValue { 167 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 168 | } 169 | if actualValue, expectedValue := m.Contains(1, "x"), true; actualValue != expectedValue { 170 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 171 | } 172 | if actualValue, expectedValue := m.Contains(1, "z"), false; actualValue != expectedValue { 173 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 174 | } 175 | if actualValue, expectedValue := m.ContainsKey(1), true; actualValue != expectedValue { 176 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 177 | } 178 | if actualValue, expectedValue := m.ContainsKey(5), false; actualValue != expectedValue { 179 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 180 | } 181 | if actualValue, expectedValue := m.ContainsValue("x"), true; actualValue != expectedValue { 182 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 183 | } 184 | if actualValue, expectedValue := m.ContainsValue("z"), false; actualValue != expectedValue { 185 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 186 | } 187 | } 188 | func TestRemove(t *testing.T) { 189 | m := New() 190 | m.Put(5, "e") 191 | m.Put(6, "f") 192 | m.Put(7, "g") 193 | m.Put(3, "c") 194 | m.Put(4, "d") 195 | m.Put(1, "x") 196 | m.Put(2, "b") 197 | m.Put(1, "a") 198 | 199 | m.Remove(5, "n") 200 | m.Remove(6, "f") 201 | m.Remove(7, "g") 202 | m.Remove(8, "h") 203 | m.Remove(5, "e") 204 | 205 | if actualValue := m.Size(); actualValue != 5 { 206 | t.Errorf("expected %v, got %v", 5, actualValue) 207 | } 208 | if actualValue, expectedValue := m.Keys(), []interface{}{1, 1, 2, 3, 4}; !sameElements(actualValue, expectedValue) { 209 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 210 | } 211 | if actualValue, expectedValue := m.KeySet(), []interface{}{1, 2, 3, 4}; !sameElements(actualValue, expectedValue) { 212 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 213 | } 214 | if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "x"}; !sameElements(actualValue, expectedValue) { 215 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 216 | } 217 | 218 | var expectedValue = []multimap.Entry{ 219 | multimap.Entry{Key: 1, Value: "a"}, 220 | multimap.Entry{Key: 1, Value: "x"}, 221 | multimap.Entry{Key: 2, Value: "b"}, 222 | multimap.Entry{Key: 3, Value: "c"}, 223 | multimap.Entry{Key: 4, Value: "d"}, 224 | } 225 | if actualValue := m.Entries(); !sameEntries(actualValue, expectedValue) { 226 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 227 | } 228 | 229 | tests := []struct { 230 | key interface{} 231 | expectedValue []interface{} 232 | expectedFound bool 233 | }{ 234 | {1, []interface{}{"a", "x"}, true}, 235 | {2, []interface{}{"b"}, true}, 236 | {3, []interface{}{"c"}, true}, 237 | {4, []interface{}{"d"}, true}, 238 | {5, nil, false}, 239 | {6, nil, false}, 240 | {7, nil, false}, 241 | {8, nil, false}, 242 | {9, nil, false}, 243 | } 244 | 245 | for i, test := range tests { 246 | actualValue, actualFound := m.Get(test.key) 247 | if !sameElements(actualValue, test.expectedValue) || actualFound != test.expectedFound { 248 | t.Errorf("test %d: expected %v, got: %v ", i+1, test.expectedValue, actualValue) 249 | } 250 | } 251 | 252 | m.Remove(1, "a") 253 | m.Remove(4, "d") 254 | m.Remove(1, "x") 255 | m.Remove(3, "c") 256 | m.Remove(2, "x") 257 | m.Remove(2, "b") 258 | 259 | if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue { 260 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 261 | } 262 | if actualValue, expectedValue := fmt.Sprintf("%s", m.KeySet()), "[]"; actualValue != expectedValue { 263 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 264 | } 265 | if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue { 266 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 267 | } 268 | if actualValue, expectedValue := fmt.Sprintf("%s", m.Entries()), "[]"; actualValue != expectedValue { 269 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 270 | } 271 | if actualValue := m.Size(); actualValue != 0 { 272 | t.Errorf("expected %v, got %v", 0, actualValue) 273 | } 274 | if actualValue := m.Empty(); actualValue != true { 275 | t.Errorf("expected %v, got %v", true, actualValue) 276 | } 277 | } 278 | 279 | func TestRemoveAll(t *testing.T) { 280 | m := New() 281 | m.Put(5, "e") 282 | m.Put(6, "f") 283 | m.Put(7, "g") 284 | m.Put(3, "c") 285 | m.Put(4, "d") 286 | m.Put(1, "x") 287 | m.Put(2, "b") 288 | m.Put(1, "a") 289 | 290 | m.RemoveAll(5) 291 | m.RemoveAll(6) 292 | m.RemoveAll(7) 293 | m.RemoveAll(8) 294 | m.RemoveAll(5) 295 | m.RemoveAll(1) 296 | m.RemoveAll(3) 297 | m.RemoveAll(2) 298 | m.RemoveAll(2) 299 | m.RemoveAll(4) 300 | m.RemoveAll(9) 301 | 302 | if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue { 303 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 304 | } 305 | if actualValue, expectedValue := fmt.Sprintf("%s", m.KeySet()), "[]"; actualValue != expectedValue { 306 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 307 | } 308 | if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue { 309 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 310 | } 311 | if actualValue, expectedValue := fmt.Sprintf("%s", m.Entries()), "[]"; actualValue != expectedValue { 312 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 313 | } 314 | if actualValue := m.Size(); actualValue != 0 { 315 | t.Errorf("expected %v, got %v", 0, actualValue) 316 | } 317 | if actualValue := m.Empty(); actualValue != true { 318 | t.Errorf("expected %v, got %v", true, actualValue) 319 | } 320 | 321 | tests := []struct { 322 | key interface{} 323 | expectedValue []interface{} 324 | expectedFound bool 325 | }{ 326 | {1, nil, false}, 327 | {2, nil, false}, 328 | {3, nil, false}, 329 | {4, nil, false}, 330 | {5, nil, false}, 331 | {6, nil, false}, 332 | {7, nil, false}, 333 | {8, nil, false}, 334 | {9, nil, false}, 335 | } 336 | 337 | for i, test := range tests { 338 | actualValue, actualFound := m.Get(test.key) 339 | if !sameElements(actualValue, test.expectedValue) || actualFound != test.expectedFound { 340 | t.Errorf("test %d: expected %v, got: %v ", i+1, test.expectedValue, actualValue) 341 | } 342 | } 343 | } 344 | 345 | // Helper function to check equality of keys/values. 346 | func sameElements(a []interface{}, b []interface{}) bool { 347 | if len(a) != len(b) { 348 | return false 349 | } 350 | for _, av := range a { 351 | found := false 352 | for _, bv := range b { 353 | if av == bv { 354 | found = true 355 | break 356 | } 357 | } 358 | if !found { 359 | return false 360 | } 361 | } 362 | return true 363 | } 364 | 365 | // Helper function to check equality of entries. 366 | func sameEntries(a []multimap.Entry, b []multimap.Entry) bool { 367 | if len(a) != len(b) { 368 | return false 369 | } 370 | for _, av := range a { 371 | found := false 372 | for _, bv := range b { 373 | if av.Key == bv.Key && av.Value == bv.Value { 374 | found = true 375 | break 376 | } 377 | } 378 | if !found { 379 | return false 380 | } 381 | } 382 | return true 383 | } 384 | 385 | // Utilities for Benchmarking 386 | func benchmarkGet(b *testing.B, m *MultiMap, size int) { 387 | for i := 0; i < b.N; i++ { 388 | for n := 0; n < size; n++ { 389 | m.Get(n) 390 | } 391 | } 392 | } 393 | 394 | func benchmarkPut(b *testing.B, m *MultiMap, size int) { 395 | for i := 0; i < b.N; i++ { 396 | for n := 0; n < size; n++ { 397 | m.Put(n, struct{}{}) 398 | } 399 | } 400 | } 401 | 402 | func benchmarkPutAll(b *testing.B, m *MultiMap, size int) { 403 | v := make([]interface{}, 0) 404 | v = append(v, struct{}{}) 405 | for i := 0; i < b.N; i++ { 406 | for n := 0; n < size; n++ { 407 | m.PutAll(n, v) 408 | } 409 | } 410 | } 411 | 412 | func benchmarkRemove(b *testing.B, m *MultiMap, size int) { 413 | for i := 0; i < b.N; i++ { 414 | for n := 0; n < size; n++ { 415 | m.Remove(n, struct{}{}) 416 | } 417 | } 418 | } 419 | 420 | func benchmarkRemoveAll(b *testing.B, m *MultiMap, size int) { 421 | for i := 0; i < b.N; i++ { 422 | for n := 0; n < size; n++ { 423 | m.RemoveAll(n) 424 | } 425 | } 426 | } 427 | 428 | func BenchmarkMultiMapGet100(b *testing.B) { 429 | b.StopTimer() 430 | size := 100 431 | m := New() 432 | for n := 0; n < size; n++ { 433 | m.Put(n, struct{}{}) 434 | } 435 | b.StartTimer() 436 | benchmarkGet(b, m, size) 437 | } 438 | 439 | func BenchmarkMultiMapGet1000(b *testing.B) { 440 | b.StopTimer() 441 | size := 1000 442 | m := New() 443 | for n := 0; n < size; n++ { 444 | m.Put(n, struct{}{}) 445 | } 446 | b.StartTimer() 447 | benchmarkGet(b, m, size) 448 | } 449 | 450 | func BenchmarkMultiMapGet10000(b *testing.B) { 451 | b.StopTimer() 452 | size := 10000 453 | m := New() 454 | for n := 0; n < size; n++ { 455 | m.Put(n, struct{}{}) 456 | } 457 | b.StartTimer() 458 | benchmarkGet(b, m, size) 459 | } 460 | 461 | func BenchmarkMultiMapGet100000(b *testing.B) { 462 | b.StopTimer() 463 | size := 100000 464 | m := New() 465 | for n := 0; n < size; n++ { 466 | m.Put(n, struct{}{}) 467 | } 468 | b.StartTimer() 469 | benchmarkGet(b, m, size) 470 | } 471 | 472 | func BenchmarkMultiMapPut100(b *testing.B) { 473 | b.StopTimer() 474 | size := 100 475 | m := New() 476 | b.StartTimer() 477 | benchmarkPut(b, m, size) 478 | } 479 | 480 | func BenchmarkMultiMapPut1000(b *testing.B) { 481 | b.StopTimer() 482 | size := 1000 483 | m := New() 484 | for n := 0; n < size; n++ { 485 | m.Put(n, struct{}{}) 486 | } 487 | b.StartTimer() 488 | benchmarkPut(b, m, size) 489 | } 490 | 491 | func BenchmarkMultiMapPut10000(b *testing.B) { 492 | b.StopTimer() 493 | size := 10000 494 | m := New() 495 | for n := 0; n < size; n++ { 496 | m.Put(n, struct{}{}) 497 | } 498 | b.StartTimer() 499 | benchmarkPut(b, m, size) 500 | } 501 | 502 | func BenchmarkMultiMapPut100000(b *testing.B) { 503 | b.StopTimer() 504 | size := 100000 505 | m := New() 506 | for n := 0; n < size; n++ { 507 | m.Put(n, struct{}{}) 508 | } 509 | b.StartTimer() 510 | benchmarkPut(b, m, size) 511 | } 512 | 513 | func BenchmarkMultiMapPutAll100(b *testing.B) { 514 | b.StopTimer() 515 | size := 100 516 | m := New() 517 | b.StartTimer() 518 | benchmarkPutAll(b, m, size) 519 | } 520 | 521 | func BenchmarkMultiMapPutAll1000(b *testing.B) { 522 | b.StopTimer() 523 | size := 1000 524 | m := New() 525 | for n := 0; n < size; n++ { 526 | m.Put(n, struct{}{}) 527 | } 528 | b.StartTimer() 529 | benchmarkPutAll(b, m, size) 530 | } 531 | 532 | func BenchmarkMultiMapPutAll10000(b *testing.B) { 533 | b.StopTimer() 534 | size := 10000 535 | m := New() 536 | for n := 0; n < size; n++ { 537 | m.Put(n, struct{}{}) 538 | } 539 | b.StartTimer() 540 | benchmarkPutAll(b, m, size) 541 | } 542 | 543 | func BenchmarkMultiMapPutAll100000(b *testing.B) { 544 | b.StopTimer() 545 | size := 100000 546 | m := New() 547 | for n := 0; n < size; n++ { 548 | m.Put(n, struct{}{}) 549 | } 550 | b.StartTimer() 551 | benchmarkPutAll(b, m, size) 552 | } 553 | 554 | func BenchmarkMultiMapRemove100(b *testing.B) { 555 | b.StopTimer() 556 | size := 100 557 | m := New() 558 | for n := 0; n < size; n++ { 559 | m.Put(n, struct{}{}) 560 | } 561 | b.StartTimer() 562 | benchmarkRemove(b, m, size) 563 | } 564 | 565 | func BenchmarkMultiMapRemove1000(b *testing.B) { 566 | b.StopTimer() 567 | size := 1000 568 | m := New() 569 | for n := 0; n < size; n++ { 570 | m.Put(n, struct{}{}) 571 | } 572 | b.StartTimer() 573 | benchmarkRemove(b, m, size) 574 | } 575 | 576 | func BenchmarkMultiMapRemove10000(b *testing.B) { 577 | b.StopTimer() 578 | size := 10000 579 | m := New() 580 | for n := 0; n < size; n++ { 581 | m.Put(n, struct{}{}) 582 | } 583 | b.StartTimer() 584 | benchmarkRemove(b, m, size) 585 | } 586 | 587 | func BenchmarkMultiMapRemove100000(b *testing.B) { 588 | b.StopTimer() 589 | size := 100000 590 | m := New() 591 | for n := 0; n < size; n++ { 592 | m.Put(n, struct{}{}) 593 | } 594 | b.StartTimer() 595 | benchmarkRemove(b, m, size) 596 | } 597 | 598 | func BenchmarkMultiMapRemoveAll100(b *testing.B) { 599 | b.StopTimer() 600 | size := 100 601 | m := New() 602 | for n := 0; n < size; n++ { 603 | m.Put(n, struct{}{}) 604 | } 605 | b.StartTimer() 606 | benchmarkRemoveAll(b, m, size) 607 | } 608 | 609 | func BenchmarkMultiMapRemoveAll1000(b *testing.B) { 610 | b.StopTimer() 611 | size := 1000 612 | m := New() 613 | for n := 0; n < size; n++ { 614 | m.Put(n, struct{}{}) 615 | } 616 | b.StartTimer() 617 | benchmarkRemoveAll(b, m, size) 618 | } 619 | 620 | func BenchmarkMultiMapRemoveAll10000(b *testing.B) { 621 | b.StopTimer() 622 | size := 10000 623 | m := New() 624 | for n := 0; n < size; n++ { 625 | m.Put(n, struct{}{}) 626 | } 627 | b.StartTimer() 628 | benchmarkRemoveAll(b, m, size) 629 | } 630 | 631 | func BenchmarkMultiMapRemoveAll100000(b *testing.B) { 632 | b.StopTimer() 633 | size := 100000 634 | m := New() 635 | for n := 0; n < size; n++ { 636 | m.Put(n, struct{}{}) 637 | } 638 | b.StartTimer() 639 | benchmarkRemoveAll(b, m, size) 640 | } 641 | -------------------------------------------------------------------------------- /slicemultimap/example_test.go: -------------------------------------------------------------------------------- 1 | package slicemultimap_test 2 | 3 | import ( 4 | "fmt" 5 | "sort" 6 | "strings" 7 | 8 | "github.com/jwangsadinata/go-multimap/slicemultimap" 9 | ) 10 | 11 | // The following examples is to demonstrate basic usage of MultiMap. 12 | func ExampleMultiMap_Clear() { 13 | // Create a new multimap 14 | m := slicemultimap.New() // empty 15 | 16 | // Put some contents to the multimap. 17 | m.Put(1, "x") // 1->x 18 | m.Put(2, "b") // 1->x, 2->b 19 | m.Put(1, "a") // 1->a, 1->x, 2->b 20 | 21 | // Clear the current map. 22 | m.Clear() // empty 23 | 24 | // Verify that it is empty. 25 | fmt.Printf("%v\n", m.Empty()) 26 | fmt.Printf("%v\n", m.Size()) 27 | 28 | // Output: 29 | // true 30 | // 0 31 | } 32 | 33 | func ExampleMultiMap_Contains() { 34 | // Create a new multimap 35 | m := slicemultimap.New() // empty 36 | 37 | // Put some contents to the multimap. 38 | m.Put(1, "x") // 1->x 39 | m.Put(2, "b") // 1->x, 2->b 40 | m.Put(1, "a") // 1->a, 1->x, 2->b 41 | 42 | // Check whether the multimap contains a certain key/value pair. 43 | found := m.Contains(1, "a") // true 44 | fmt.Printf("%v\n", found) 45 | 46 | found = m.Contains(1, "b") // false 47 | fmt.Printf("%v\n", found) 48 | 49 | found = m.Contains(2, "b") // true 50 | fmt.Printf("%v\n", found) 51 | 52 | // Output: 53 | // true 54 | // false 55 | // true 56 | } 57 | 58 | func ExampleMultiMap_ContainsKey() { 59 | // Create a new multimap 60 | m := slicemultimap.New() // empty 61 | 62 | // Put some contents to the multimap. 63 | m.Put(1, "x") // 1->x 64 | m.Put(2, "b") // 1->x, 2->b 65 | m.Put(1, "a") // 1->a, 1->x, 2->b 66 | 67 | // Check whether the multimap contains a certain key. 68 | found := m.ContainsKey(1) // true 69 | fmt.Printf("%v\n", found) 70 | 71 | found = m.ContainsKey(2) // true 72 | fmt.Printf("%v\n", found) 73 | 74 | found = m.ContainsKey(3) // true 75 | fmt.Printf("%v\n", found) 76 | 77 | // Output: 78 | // true 79 | // true 80 | // false 81 | } 82 | 83 | func ExampleMultiMap_ContainsValue() { 84 | // Create a new multimap 85 | m := slicemultimap.New() // empty 86 | 87 | // Put some contents to the multimap. 88 | m.Put(1, "x") // 1->x 89 | m.Put(2, "b") // 1->x, 2->b 90 | m.Put(1, "a") // 1->a, 1->x, 2->b 91 | 92 | // Check whether the multimap contains a certain value. 93 | found := m.ContainsValue("a") // true 94 | fmt.Printf("%v\n", found) 95 | 96 | found = m.ContainsValue("b") // true 97 | fmt.Printf("%v\n", found) 98 | 99 | found = m.ContainsValue("c") // true 100 | fmt.Printf("%v\n", found) 101 | 102 | // Output: 103 | // true 104 | // true 105 | // false 106 | } 107 | 108 | func ExampleMultiMap_Get() { 109 | // Create a new multimap 110 | m := slicemultimap.New() // empty 111 | 112 | // Put some contents to the multimap. 113 | m.Put(1, "x") // 1->x 114 | m.Put(2, "b") // 1->x, 2->b 115 | m.Put(1, "a") // 1->a, 1->x, 2->b 116 | 117 | // Retrieve values from the map. 118 | value, found := m.Get(3) // nil, false 119 | fmt.Printf("%v, %v\n", value, found) 120 | 121 | value, found = m.Get(2) // {b}, true 122 | fmt.Printf("%v, %v\n", value, found) 123 | 124 | value, found = m.Get(1) // {a, x}, true (random order) 125 | 126 | // Workaround for test output consistency: 127 | tmp := make([]string, len(value)) 128 | count := 0 129 | for _, s := range value { 130 | tmp[count] = s.(string) 131 | count++ 132 | } 133 | sort.Strings(tmp) 134 | fmt.Printf("%v, %v\n", tmp, found) 135 | 136 | // Output: 137 | // [], false 138 | // [b], true 139 | // [a x], true 140 | } 141 | 142 | func ExampleMultiMap_Put() { 143 | // Create a new multimap 144 | m := slicemultimap.New() // empty 145 | 146 | // Put some contents to the multimap. 147 | m.Put(1, "x") // 1->x 148 | m.Put(2, "b") // 1->x, 2->b 149 | m.Put(1, "a") // 1->a, 1->x, 2->b 150 | 151 | // Verify that the map has the right size. 152 | fmt.Println(m.Size()) 153 | 154 | // Output: 155 | // 3 156 | } 157 | 158 | func ExampleMultiMap_Entries() { 159 | // Create a new multimap 160 | m := slicemultimap.New() // empty 161 | 162 | // Put some contents to the multimap. 163 | m.Put(1, "x") // 1->x 164 | m.Put(2, "b") // 1->x, 2->b 165 | m.Put(1, "a") // 1->a, 1->x, 2->b 166 | 167 | // Retrieve all the keys in the map. 168 | entries := m.Entries() // {1,a}, {1,x}, {2,b} (random order) 169 | 170 | // Workaround for test output consistency. 171 | tmp := make([]struct { 172 | Key int 173 | Value string 174 | }, len(entries)) 175 | count := 0 176 | for _, e := range entries { 177 | tmp[count] = struct { 178 | Key int 179 | Value string 180 | }{e.Key.(int), e.Value.(string)} 181 | count++ 182 | } 183 | sort.Sort(byKeyThenValue(tmp)) 184 | fmt.Printf("%v\n", tmp) 185 | 186 | // Output: 187 | // [{1 a} {1 x} {2 b}] 188 | } 189 | 190 | func ExampleMultiMap_Keys() { 191 | // Create a new multimap 192 | m := slicemultimap.New() // empty 193 | 194 | // Put some contents to the multimap. 195 | m.Put(1, "x") // 1->x 196 | m.Put(2, "b") // 1->x, 2->b 197 | m.Put(1, "a") // 1->a, 1->x, 2->b 198 | 199 | // Retrieve all the keys in the multimap. 200 | keys := m.Keys() // 1, 1, 2 (random order) 201 | 202 | // Workaround for test output consistency. 203 | tmp := make([]int, len(keys)) 204 | count := 0 205 | for _, key := range keys { 206 | tmp[count] = key.(int) 207 | count++ 208 | } 209 | sort.Ints(tmp) 210 | fmt.Printf("%v\n", tmp) 211 | 212 | // Output: 213 | // [1 1 2] 214 | } 215 | 216 | func ExampleMultiMap_KeySet() { 217 | // Create a new multimap 218 | m := slicemultimap.New() // empty 219 | 220 | // Put some contents to the multimap. 221 | m.Put(1, "x") // 1->x 222 | m.Put(2, "b") // 1->x, 2->b 223 | m.Put(1, "a") // 1->a, 1->x, 2->b 224 | 225 | // Retrieve all the distinct keys in the multimap. 226 | keys := m.KeySet() // 1, 2 (random order) 227 | 228 | // Workaround for test output consistency. 229 | tmp := make([]int, len(keys)) 230 | count := 0 231 | for _, key := range keys { 232 | tmp[count] = key.(int) 233 | count++ 234 | } 235 | sort.Ints(tmp) 236 | fmt.Printf("%v\n", tmp) 237 | 238 | // Output: 239 | // [1 2] 240 | } 241 | 242 | func ExampleMultiMap_Values() { 243 | // Create a new multimap 244 | m := slicemultimap.New() // empty 245 | 246 | // Put some contents to the multimap. 247 | m.Put(1, "x") // 1->x 248 | m.Put(2, "b") // 1->x, 2->b 249 | m.Put(1, "a") // 1->a, 1->x, 2->b 250 | 251 | // Retrieve all the keys in the map. 252 | values := m.Values() // a, b, x (random order) 253 | 254 | // Workaround for test output consistency. 255 | tmp := make([]string, len(values)) 256 | count := 0 257 | for _, value := range values { 258 | tmp[count] = value.(string) 259 | count++ 260 | } 261 | sort.Strings(tmp) 262 | fmt.Printf("%v\n", tmp) 263 | 264 | // Output: 265 | // [a b x] 266 | } 267 | 268 | func ExampleMultiMap_Remove() { 269 | // Create a new multimap 270 | m := slicemultimap.New() // empty 271 | 272 | // Put some contents to the multimap. 273 | m.Put(1, "x") // 1->x 274 | m.Put(2, "b") // 1->x, 2->b 275 | m.Put(1, "a") // 1->a, 1->x, 2->b 276 | 277 | // Remove a key/value pair from the multimap. 278 | m.Remove(2, "b") 279 | 280 | // Verify that the map has less number of key/value pair. 281 | fmt.Println(m.Size()) // 2 282 | 283 | // Also, verify that there are no more (2, "b") key/value pair. 284 | value, found := m.Get(2) 285 | fmt.Printf("%v, %v", value, found) // nil, false 286 | 287 | // Output: 288 | // 2 289 | // [], false 290 | } 291 | 292 | func ExampleMultiMap_RemoveAll() { 293 | // Create a new multimap 294 | m := slicemultimap.New() // empty 295 | 296 | // Put some contents to the multimap. 297 | m.Put(1, "x") // 1->x 298 | m.Put(2, "b") // 1->x, 2->b 299 | m.Put(1, "a") // 1->a, 1->x, 2->b 300 | 301 | // Remove a key/value pair from the multimap. 302 | m.RemoveAll(1) 303 | 304 | // Verify that the map has less number of key/value pair. 305 | fmt.Println(m.Size()) // 1 306 | 307 | // Also, verify that there are no more values with key 1. 308 | value, found := m.Get(1) 309 | fmt.Printf("%v, %v", value, found) // nil, false 310 | 311 | // Output: 312 | // 1 313 | // [], false 314 | } 315 | 316 | // Helper for sorting entries. 317 | type byKeyThenValue []struct { 318 | Key int 319 | Value string 320 | } 321 | 322 | func (a byKeyThenValue) Len() int { return len(a) } 323 | func (a byKeyThenValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 324 | func (a byKeyThenValue) Less(i, j int) bool { 325 | if a[i].Key < a[j].Key { 326 | return true 327 | } else if a[i].Key > a[j].Key { 328 | return false 329 | } else { 330 | return strings.Compare(a[i].Value, a[j].Value) < 0 331 | } 332 | } 333 | -------------------------------------------------------------------------------- /slicemultimap/slicemultimap.go: -------------------------------------------------------------------------------- 1 | // Package slicemultimap implements a multimap backed by go's native slice. 2 | // 3 | // A slicemultimap is a multimap that can hold duplicate key-value pairs 4 | // and that maintains the insertion ordering of values for a given key. 5 | // 6 | // This multimap is typically known as ListMultimap in other languages. 7 | // 8 | // Elements are unordered in the map. 9 | // 10 | // Structure is not thread safe. 11 | // 12 | package slicemultimap 13 | 14 | import multimap "github.com/jwangsadinata/go-multimap" 15 | 16 | // MultiMap holds the elements in go's native map. 17 | type MultiMap struct { 18 | m map[interface{}][]interface{} 19 | } 20 | 21 | // New instantiates a new multimap. 22 | func New() *MultiMap { 23 | return &MultiMap{m: make(map[interface{}][]interface{})} 24 | } 25 | 26 | // Get searches the element in the multimap by key. 27 | // It returns its value or nil if key is not found in multimap. 28 | // Second return parameter is true if key was found, otherwise false. 29 | func (m *MultiMap) Get(key interface{}) (values []interface{}, found bool) { 30 | values, found = m.m[key] 31 | return 32 | } 33 | 34 | // Put stores a key-value pair in this multimap. 35 | func (m *MultiMap) Put(key interface{}, value interface{}) { 36 | m.m[key] = append(m.m[key], value) 37 | } 38 | 39 | // PutAll stores a key-value pair in this multimap for each of the values, all using the same key key. 40 | func (m *MultiMap) PutAll(key interface{}, values []interface{}) { 41 | for _, value := range values { 42 | m.Put(key, value) 43 | } 44 | } 45 | 46 | // Contains returns true if this multimap contains at least one key-value pair with the key key and the value value. 47 | func (m *MultiMap) Contains(key interface{}, value interface{}) bool { 48 | values, found := m.m[key] 49 | for _, v := range values { 50 | if v == value { 51 | return true && found 52 | } 53 | } 54 | return false && found 55 | } 56 | 57 | // ContainsKey returns true if this multimap contains at least one key-value pair with the key key. 58 | func (m *MultiMap) ContainsKey(key interface{}) (found bool) { 59 | _, found = m.m[key] 60 | return 61 | } 62 | 63 | // ContainsValue returns true if this multimap contains at least one key-value pair with the value value. 64 | func (m *MultiMap) ContainsValue(value interface{}) bool { 65 | for _, values := range m.m { 66 | for _, v := range values { 67 | if v == value { 68 | return true 69 | } 70 | } 71 | } 72 | return false 73 | } 74 | 75 | // Remove removes a single key-value pair from this multimap, if such exists. 76 | func (m *MultiMap) Remove(key interface{}, value interface{}) { 77 | values, found := m.m[key] 78 | if found { 79 | for i, v := range values { 80 | if v == value { 81 | m.m[key] = append(values[:i], values[i+1:]...) 82 | } 83 | } 84 | } 85 | if len(m.m[key]) == 0 { 86 | delete(m.m, key) 87 | } 88 | } 89 | 90 | // RemoveAll removes all values associated with the key from the multimap. 91 | func (m *MultiMap) RemoveAll(key interface{}) { 92 | delete(m.m, key) 93 | } 94 | 95 | // Empty returns true if multimap does not contain any key-value pairs. 96 | func (m *MultiMap) Empty() bool { 97 | return m.Size() == 0 98 | } 99 | 100 | // Size returns number of key-value pairs in the multimap. 101 | func (m *MultiMap) Size() int { 102 | size := 0 103 | for _, value := range m.m { 104 | size += len(value) 105 | } 106 | return size 107 | } 108 | 109 | // Keys returns a view collection containing the key from each key-value pair in this multimap. 110 | // This is done without collapsing duplicates. 111 | func (m *MultiMap) Keys() []interface{} { 112 | keys := make([]interface{}, m.Size()) 113 | count := 0 114 | for key, value := range m.m { 115 | for range value { 116 | keys[count] = key 117 | count++ 118 | } 119 | } 120 | return keys 121 | } 122 | 123 | // KeySet returns all distinct keys contained in this multimap. 124 | func (m *MultiMap) KeySet() []interface{} { 125 | keys := make([]interface{}, len(m.m)) 126 | count := 0 127 | for key := range m.m { 128 | keys[count] = key 129 | count++ 130 | } 131 | return keys 132 | } 133 | 134 | // Values returns all values from each key-value pair contained in this multimap. 135 | // This is done without collapsing duplicates. (size of Values() = MultiMap.Size()). 136 | func (m *MultiMap) Values() []interface{} { 137 | values := make([]interface{}, m.Size()) 138 | count := 0 139 | for _, vs := range m.m { 140 | for _, value := range vs { 141 | values[count] = value 142 | count++ 143 | } 144 | } 145 | return values 146 | } 147 | 148 | // Entries view collection of all key-value pairs contained in this multimap. 149 | // The return type is a slice of multimap.Entry instances. 150 | // Retrieving the key and value from the entries result will be as trivial as: 151 | // - var entry = m.Entries()[0] 152 | // - var key = entry.Key 153 | // - var value = entry.Value 154 | func (m *MultiMap) Entries() []multimap.Entry { 155 | entries := make([]multimap.Entry, m.Size()) 156 | count := 0 157 | for key, values := range m.m { 158 | for _, value := range values { 159 | entries[count] = multimap.Entry{Key: key, Value: value} 160 | count++ 161 | } 162 | } 163 | return entries 164 | } 165 | 166 | // Clear removes all elements from the map. 167 | func (m *MultiMap) Clear() { 168 | m.m = make(map[interface{}][]interface{}) 169 | } 170 | -------------------------------------------------------------------------------- /slicemultimap/slicemultimap_test.go: -------------------------------------------------------------------------------- 1 | package slicemultimap 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | multimap "github.com/jwangsadinata/go-multimap" 8 | ) 9 | 10 | func AssertMultiMapImplementation(t *testing.T) { 11 | var _ multimap.MultiMap = New() 12 | } 13 | 14 | func TestClear(t *testing.T) { 15 | m := New() 16 | m.Put(5, "e") 17 | m.Put(6, "f") 18 | m.Put(7, "g") 19 | m.Put(3, "c") 20 | m.Put(4, "d") 21 | m.Put(1, "x") 22 | m.Put(2, "b") 23 | m.Put(1, "a") 24 | 25 | if actualValue := m.Size(); actualValue != 8 { 26 | t.Errorf("expected %v, got %v", 8, actualValue) 27 | } 28 | if actualEmpty := m.Empty(); actualEmpty != false { 29 | t.Errorf("expected an empty multimap: %v, got %v", false, actualEmpty) 30 | } 31 | 32 | m.Clear() 33 | 34 | if actualValue := m.Size(); actualValue != 0 { 35 | t.Errorf("expected %v, got %v", 0, actualValue) 36 | } 37 | if actualEmpty := m.Empty(); actualEmpty != true { 38 | t.Errorf("expected an empty multimap: %v, got %v", true, actualEmpty) 39 | } 40 | } 41 | func TestPut(t *testing.T) { 42 | m := New() 43 | m.Put(5, "e") 44 | m.Put(6, "f") 45 | m.Put(7, "g") 46 | m.Put(3, "c") 47 | m.Put(4, "d") 48 | m.Put(1, "x") 49 | m.Put(2, "b") 50 | m.Put(1, "a") 51 | 52 | if actualValue := m.Size(); actualValue != 8 { 53 | t.Errorf("expected %v, got %v", 8, actualValue) 54 | } 55 | if actualValue, expectedValue := m.Keys(), []interface{}{1, 1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) { 56 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 57 | } 58 | if actualValue, expectedValue := m.KeySet(), []interface{}{1, 2, 3, 4, 5, 6, 7}; !sameElements(actualValue, expectedValue) { 59 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 60 | } 61 | if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "e", "f", "g", "x"}; !sameElements(actualValue, expectedValue) { 62 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 63 | } 64 | 65 | var expectedValue = []multimap.Entry{ 66 | multimap.Entry{Key: 1, Value: "a"}, 67 | multimap.Entry{Key: 1, Value: "x"}, 68 | multimap.Entry{Key: 2, Value: "b"}, 69 | multimap.Entry{Key: 3, Value: "c"}, 70 | multimap.Entry{Key: 4, Value: "d"}, 71 | multimap.Entry{Key: 5, Value: "e"}, 72 | multimap.Entry{Key: 6, Value: "f"}, 73 | multimap.Entry{Key: 7, Value: "g"}, 74 | } 75 | if actualValue := m.Entries(); !sameEntries(actualValue, expectedValue) { 76 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 77 | } 78 | 79 | tests := []struct { 80 | key interface{} 81 | expectedValue []interface{} 82 | expectedFound bool 83 | }{ 84 | {1, []interface{}{"a", "x"}, true}, 85 | {2, []interface{}{"b"}, true}, 86 | {3, []interface{}{"c"}, true}, 87 | {4, []interface{}{"d"}, true}, 88 | {5, []interface{}{"e"}, true}, 89 | {6, []interface{}{"f"}, true}, 90 | {7, []interface{}{"g"}, true}, 91 | {8, nil, false}, 92 | {9, nil, false}, 93 | } 94 | 95 | for i, test := range tests { 96 | actualValue, actualFound := m.Get(test.key) 97 | if !sameElements(actualValue, test.expectedValue) || actualFound != test.expectedFound { 98 | t.Errorf("test %d: expected %v, got: %v ", i+1, test.expectedValue, actualValue) 99 | } 100 | } 101 | } 102 | 103 | func TestPutAll(t *testing.T) { 104 | m := New() 105 | m.Put(3, "c") 106 | m.Put(4, "d") 107 | m.Put(2, "b") 108 | m.PutAll(1, []interface{}{"a", "x", "y"}) 109 | 110 | if actualValue := m.Size(); actualValue != 6 { 111 | t.Errorf("expected %v, got %v", 6, actualValue) 112 | } 113 | if actualValue, expectedValue := m.Keys(), []interface{}{1, 1, 1, 2, 3, 4}; !sameElements(actualValue, expectedValue) { 114 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 115 | } 116 | if actualValue, expectedValue := m.KeySet(), []interface{}{1, 2, 3, 4}; !sameElements(actualValue, expectedValue) { 117 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 118 | } 119 | if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "x", "y"}; !sameElements(actualValue, expectedValue) { 120 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 121 | } 122 | 123 | var expectedValue = []multimap.Entry{ 124 | multimap.Entry{Key: 1, Value: "a"}, 125 | multimap.Entry{Key: 1, Value: "x"}, 126 | multimap.Entry{Key: 1, Value: "y"}, 127 | multimap.Entry{Key: 2, Value: "b"}, 128 | multimap.Entry{Key: 3, Value: "c"}, 129 | multimap.Entry{Key: 4, Value: "d"}, 130 | } 131 | if actualValue := m.Entries(); !sameEntries(actualValue, expectedValue) { 132 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 133 | } 134 | 135 | tests := []struct { 136 | key interface{} 137 | expectedValue []interface{} 138 | expectedFound bool 139 | }{ 140 | {1, []interface{}{"a", "x", "y"}, true}, 141 | {2, []interface{}{"b"}, true}, 142 | {3, []interface{}{"c"}, true}, 143 | {4, []interface{}{"d"}, true}, 144 | {5, nil, false}, 145 | {6, nil, false}, 146 | } 147 | 148 | for i, test := range tests { 149 | // Test for retrievals. 150 | actualValue, actualFound := m.Get(test.key) 151 | if !sameElements(actualValue, test.expectedValue) || actualFound != test.expectedFound { 152 | t.Errorf("test %d: expected %v, got: %v ", i+1, test.expectedValue, actualValue) 153 | } 154 | } 155 | } 156 | 157 | func TestContains(t *testing.T) { 158 | m := New() 159 | m.Put(3, "c") 160 | m.Put(4, "d") 161 | m.Put(2, "b") 162 | m.PutAll(1, []interface{}{"a", "x", "y"}) 163 | 164 | if actualValue, expectedValue := m.Contains(1, "a"), true; actualValue != expectedValue { 165 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 166 | } 167 | if actualValue, expectedValue := m.Contains(1, "x"), true; actualValue != expectedValue { 168 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 169 | } 170 | if actualValue, expectedValue := m.Contains(1, "z"), false; actualValue != expectedValue { 171 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 172 | } 173 | if actualValue, expectedValue := m.ContainsKey(1), true; actualValue != expectedValue { 174 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 175 | } 176 | if actualValue, expectedValue := m.ContainsKey(5), false; actualValue != expectedValue { 177 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 178 | } 179 | if actualValue, expectedValue := m.ContainsValue("x"), true; actualValue != expectedValue { 180 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 181 | } 182 | if actualValue, expectedValue := m.ContainsValue("z"), false; actualValue != expectedValue { 183 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 184 | } 185 | } 186 | func TestRemove(t *testing.T) { 187 | m := New() 188 | m.Put(5, "e") 189 | m.Put(6, "f") 190 | m.Put(7, "g") 191 | m.Put(3, "c") 192 | m.Put(4, "d") 193 | m.Put(1, "x") 194 | m.Put(2, "b") 195 | m.Put(1, "a") 196 | 197 | m.Remove(5, "n") 198 | m.Remove(6, "f") 199 | m.Remove(7, "g") 200 | m.Remove(8, "h") 201 | m.Remove(5, "e") 202 | 203 | if actualValue := m.Size(); actualValue != 5 { 204 | t.Errorf("expected %v, got %v", 5, actualValue) 205 | } 206 | if actualValue, expectedValue := m.Keys(), []interface{}{1, 1, 2, 3, 4}; !sameElements(actualValue, expectedValue) { 207 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 208 | } 209 | if actualValue, expectedValue := m.KeySet(), []interface{}{1, 2, 3, 4}; !sameElements(actualValue, expectedValue) { 210 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 211 | } 212 | if actualValue, expectedValue := m.Values(), []interface{}{"a", "b", "c", "d", "x"}; !sameElements(actualValue, expectedValue) { 213 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 214 | } 215 | 216 | var expectedValue = []multimap.Entry{ 217 | multimap.Entry{Key: 1, Value: "a"}, 218 | multimap.Entry{Key: 1, Value: "x"}, 219 | multimap.Entry{Key: 2, Value: "b"}, 220 | multimap.Entry{Key: 3, Value: "c"}, 221 | multimap.Entry{Key: 4, Value: "d"}, 222 | } 223 | if actualValue := m.Entries(); !sameEntries(actualValue, expectedValue) { 224 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 225 | } 226 | 227 | tests := []struct { 228 | key interface{} 229 | expectedValue []interface{} 230 | expectedFound bool 231 | }{ 232 | {1, []interface{}{"a", "x"}, true}, 233 | {2, []interface{}{"b"}, true}, 234 | {3, []interface{}{"c"}, true}, 235 | {4, []interface{}{"d"}, true}, 236 | {5, nil, false}, 237 | {6, nil, false}, 238 | {7, nil, false}, 239 | {8, nil, false}, 240 | {9, nil, false}, 241 | } 242 | 243 | for i, test := range tests { 244 | actualValue, actualFound := m.Get(test.key) 245 | if !sameElements(actualValue, test.expectedValue) || actualFound != test.expectedFound { 246 | t.Errorf("test %d: expected %v, got: %v ", i+1, test.expectedValue, actualValue) 247 | } 248 | } 249 | 250 | m.Remove(1, "a") 251 | m.Remove(4, "d") 252 | m.Remove(1, "x") 253 | m.Remove(3, "c") 254 | m.Remove(2, "x") 255 | m.Remove(2, "b") 256 | 257 | if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue { 258 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 259 | } 260 | if actualValue, expectedValue := fmt.Sprintf("%s", m.KeySet()), "[]"; actualValue != expectedValue { 261 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 262 | } 263 | if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue { 264 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 265 | } 266 | if actualValue, expectedValue := fmt.Sprintf("%s", m.Entries()), "[]"; actualValue != expectedValue { 267 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 268 | } 269 | if actualValue := m.Size(); actualValue != 0 { 270 | t.Errorf("expected %v, got %v", 0, actualValue) 271 | } 272 | if actualValue := m.Empty(); actualValue != true { 273 | t.Errorf("expected %v, got %v", true, actualValue) 274 | } 275 | } 276 | 277 | func TestRemoveAll(t *testing.T) { 278 | m := New() 279 | m.Put(5, "e") 280 | m.Put(6, "f") 281 | m.Put(7, "g") 282 | m.Put(3, "c") 283 | m.Put(4, "d") 284 | m.Put(1, "x") 285 | m.Put(2, "b") 286 | m.Put(1, "a") 287 | 288 | m.RemoveAll(5) 289 | m.RemoveAll(6) 290 | m.RemoveAll(7) 291 | m.RemoveAll(8) 292 | m.RemoveAll(5) 293 | m.RemoveAll(1) 294 | m.RemoveAll(3) 295 | m.RemoveAll(2) 296 | m.RemoveAll(2) 297 | m.RemoveAll(4) 298 | m.RemoveAll(9) 299 | 300 | if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue { 301 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 302 | } 303 | if actualValue, expectedValue := fmt.Sprintf("%s", m.KeySet()), "[]"; actualValue != expectedValue { 304 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 305 | } 306 | if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue { 307 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 308 | } 309 | if actualValue, expectedValue := fmt.Sprintf("%s", m.Entries()), "[]"; actualValue != expectedValue { 310 | t.Errorf("expected %v, got %v", expectedValue, actualValue) 311 | } 312 | if actualValue := m.Size(); actualValue != 0 { 313 | t.Errorf("expected %v, got %v", 0, actualValue) 314 | } 315 | if actualValue := m.Empty(); actualValue != true { 316 | t.Errorf("expected %v, got %v", true, actualValue) 317 | } 318 | 319 | tests := []struct { 320 | key interface{} 321 | expectedValue []interface{} 322 | expectedFound bool 323 | }{ 324 | {1, nil, false}, 325 | {2, nil, false}, 326 | {3, nil, false}, 327 | {4, nil, false}, 328 | {5, nil, false}, 329 | {6, nil, false}, 330 | {7, nil, false}, 331 | {8, nil, false}, 332 | {9, nil, false}, 333 | } 334 | 335 | for i, test := range tests { 336 | actualValue, actualFound := m.Get(test.key) 337 | if !sameElements(actualValue, test.expectedValue) || actualFound != test.expectedFound { 338 | t.Errorf("test %d: expected %v, got: %v ", i+1, test.expectedValue, actualValue) 339 | } 340 | } 341 | } 342 | 343 | // Helper function to check equality of keys/values. 344 | func sameElements(a []interface{}, b []interface{}) bool { 345 | if len(a) != len(b) { 346 | return false 347 | } 348 | for _, av := range a { 349 | found := false 350 | for _, bv := range b { 351 | if av == bv { 352 | found = true 353 | break 354 | } 355 | } 356 | if !found { 357 | return false 358 | } 359 | } 360 | return true 361 | } 362 | 363 | // Helper function to check equality of entries. 364 | func sameEntries(a []multimap.Entry, b []multimap.Entry) bool { 365 | if len(a) != len(b) { 366 | return false 367 | } 368 | for _, av := range a { 369 | found := false 370 | for _, bv := range b { 371 | if av.Key == bv.Key && av.Value == bv.Value { 372 | found = true 373 | break 374 | } 375 | } 376 | if !found { 377 | return false 378 | } 379 | } 380 | return true 381 | } 382 | 383 | // Utilities for Benchmarking 384 | func benchmarkGet(b *testing.B, m *MultiMap, size int) { 385 | for i := 0; i < b.N; i++ { 386 | for n := 0; n < size; n++ { 387 | m.Get(n) 388 | } 389 | } 390 | } 391 | 392 | func benchmarkPut(b *testing.B, m *MultiMap, size int) { 393 | for i := 0; i < b.N; i++ { 394 | for n := 0; n < size; n++ { 395 | m.Put(n, struct{}{}) 396 | } 397 | } 398 | } 399 | 400 | func benchmarkPutAll(b *testing.B, m *MultiMap, size int) { 401 | v := make([]interface{}, 0) 402 | v = append(v, struct{}{}) 403 | for i := 0; i < b.N; i++ { 404 | for n := 0; n < size; n++ { 405 | m.PutAll(n, v) 406 | } 407 | } 408 | } 409 | 410 | func benchmarkRemove(b *testing.B, m *MultiMap, size int) { 411 | for i := 0; i < b.N; i++ { 412 | for n := 0; n < size; n++ { 413 | m.Remove(n, struct{}{}) 414 | } 415 | } 416 | } 417 | 418 | func benchmarkRemoveAll(b *testing.B, m *MultiMap, size int) { 419 | for i := 0; i < b.N; i++ { 420 | for n := 0; n < size; n++ { 421 | m.RemoveAll(n) 422 | } 423 | } 424 | } 425 | 426 | func BenchmarkMultiMapGet100(b *testing.B) { 427 | b.StopTimer() 428 | size := 100 429 | m := New() 430 | for n := 0; n < size; n++ { 431 | m.Put(n, struct{}{}) 432 | } 433 | b.StartTimer() 434 | benchmarkGet(b, m, size) 435 | } 436 | 437 | func BenchmarkMultiMapGet1000(b *testing.B) { 438 | b.StopTimer() 439 | size := 1000 440 | m := New() 441 | for n := 0; n < size; n++ { 442 | m.Put(n, struct{}{}) 443 | } 444 | b.StartTimer() 445 | benchmarkGet(b, m, size) 446 | } 447 | 448 | func BenchmarkMultiMapGet10000(b *testing.B) { 449 | b.StopTimer() 450 | size := 10000 451 | m := New() 452 | for n := 0; n < size; n++ { 453 | m.Put(n, struct{}{}) 454 | } 455 | b.StartTimer() 456 | benchmarkGet(b, m, size) 457 | } 458 | 459 | func BenchmarkMultiMapGet100000(b *testing.B) { 460 | b.StopTimer() 461 | size := 100000 462 | m := New() 463 | for n := 0; n < size; n++ { 464 | m.Put(n, struct{}{}) 465 | } 466 | b.StartTimer() 467 | benchmarkGet(b, m, size) 468 | } 469 | 470 | func BenchmarkMultiMapPut100(b *testing.B) { 471 | b.StopTimer() 472 | size := 100 473 | m := New() 474 | b.StartTimer() 475 | benchmarkPut(b, m, size) 476 | } 477 | 478 | func BenchmarkMultiMapPut1000(b *testing.B) { 479 | b.StopTimer() 480 | size := 1000 481 | m := New() 482 | for n := 0; n < size; n++ { 483 | m.Put(n, struct{}{}) 484 | } 485 | b.StartTimer() 486 | benchmarkPut(b, m, size) 487 | } 488 | 489 | func BenchmarkMultiMapPut10000(b *testing.B) { 490 | b.StopTimer() 491 | size := 10000 492 | m := New() 493 | for n := 0; n < size; n++ { 494 | m.Put(n, struct{}{}) 495 | } 496 | b.StartTimer() 497 | benchmarkPut(b, m, size) 498 | } 499 | 500 | func BenchmarkMultiMapPut100000(b *testing.B) { 501 | b.StopTimer() 502 | size := 100000 503 | m := New() 504 | for n := 0; n < size; n++ { 505 | m.Put(n, struct{}{}) 506 | } 507 | b.StartTimer() 508 | benchmarkPut(b, m, size) 509 | } 510 | 511 | func BenchmarkMultiMapPutAll100(b *testing.B) { 512 | b.StopTimer() 513 | size := 100 514 | m := New() 515 | b.StartTimer() 516 | benchmarkPutAll(b, m, size) 517 | } 518 | 519 | func BenchmarkMultiMapPutAll1000(b *testing.B) { 520 | b.StopTimer() 521 | size := 1000 522 | m := New() 523 | for n := 0; n < size; n++ { 524 | m.Put(n, struct{}{}) 525 | } 526 | b.StartTimer() 527 | benchmarkPutAll(b, m, size) 528 | } 529 | 530 | func BenchmarkMultiMapPutAll10000(b *testing.B) { 531 | b.StopTimer() 532 | size := 10000 533 | m := New() 534 | for n := 0; n < size; n++ { 535 | m.Put(n, struct{}{}) 536 | } 537 | b.StartTimer() 538 | benchmarkPutAll(b, m, size) 539 | } 540 | 541 | func BenchmarkMultiMapPutAll100000(b *testing.B) { 542 | b.StopTimer() 543 | size := 100000 544 | m := New() 545 | for n := 0; n < size; n++ { 546 | m.Put(n, struct{}{}) 547 | } 548 | b.StartTimer() 549 | benchmarkPutAll(b, m, size) 550 | } 551 | 552 | func BenchmarkMultiMapRemove100(b *testing.B) { 553 | b.StopTimer() 554 | size := 100 555 | m := New() 556 | for n := 0; n < size; n++ { 557 | m.Put(n, struct{}{}) 558 | } 559 | b.StartTimer() 560 | benchmarkRemove(b, m, size) 561 | } 562 | 563 | func BenchmarkMultiMapRemove1000(b *testing.B) { 564 | b.StopTimer() 565 | size := 1000 566 | m := New() 567 | for n := 0; n < size; n++ { 568 | m.Put(n, struct{}{}) 569 | } 570 | b.StartTimer() 571 | benchmarkRemove(b, m, size) 572 | } 573 | 574 | func BenchmarkMultiMapRemove10000(b *testing.B) { 575 | b.StopTimer() 576 | size := 10000 577 | m := New() 578 | for n := 0; n < size; n++ { 579 | m.Put(n, struct{}{}) 580 | } 581 | b.StartTimer() 582 | benchmarkRemove(b, m, size) 583 | } 584 | 585 | func BenchmarkMultiMapRemove100000(b *testing.B) { 586 | b.StopTimer() 587 | size := 100000 588 | m := New() 589 | for n := 0; n < size; n++ { 590 | m.Put(n, struct{}{}) 591 | } 592 | b.StartTimer() 593 | benchmarkRemove(b, m, size) 594 | } 595 | 596 | func BenchmarkMultiMapRemoveAll100(b *testing.B) { 597 | b.StopTimer() 598 | size := 100 599 | m := New() 600 | for n := 0; n < size; n++ { 601 | m.Put(n, struct{}{}) 602 | } 603 | b.StartTimer() 604 | benchmarkRemoveAll(b, m, size) 605 | } 606 | 607 | func BenchmarkMultiMapRemoveAll1000(b *testing.B) { 608 | b.StopTimer() 609 | size := 1000 610 | m := New() 611 | for n := 0; n < size; n++ { 612 | m.Put(n, struct{}{}) 613 | } 614 | b.StartTimer() 615 | benchmarkRemoveAll(b, m, size) 616 | } 617 | 618 | func BenchmarkMultiMapRemoveAll10000(b *testing.B) { 619 | b.StopTimer() 620 | size := 10000 621 | m := New() 622 | for n := 0; n < size; n++ { 623 | m.Put(n, struct{}{}) 624 | } 625 | b.StartTimer() 626 | benchmarkRemoveAll(b, m, size) 627 | } 628 | 629 | func BenchmarkMultiMapRemoveAll100000(b *testing.B) { 630 | b.StopTimer() 631 | size := 100000 632 | m := New() 633 | for n := 0; n < size; n++ { 634 | m.Put(n, struct{}{}) 635 | } 636 | b.StartTimer() 637 | benchmarkRemoveAll(b, m, size) 638 | } 639 | --------------------------------------------------------------------------------