├── .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 | [](https://godoc.org/github.com/jwangsadinata/go-multimap) [](https://travis-ci.org/jwangsadinata/go-multimap) [](https://goreportcard.com/report/github.com/jwangsadinata/go-multimap) [](https://coveralls.io/github/jwangsadinata/go-multimap?branch=master&service=github) [](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 |
--------------------------------------------------------------------------------