Maps

An Introduction to Maps.

Maps

Maps are Go’s built-in associative data type (sometimes called hashes or dicts in other languages). Maps are made up of key-value pairs and provide a way to store data without relying on indexing.

package main

import "fmt"

var m map[string]string

func main() {
	m = make(map[string]string)
	m["Monica"] = "Geller"
	m["Joey"] = "Tribbiani"
	fmt.Println(m["Monica"])
	fmt.Println(m["Pheobe"])
}

Output:

Geller

Question: In case array or slice, when you are trying to access out of index element (when the index does not exist), Go will throw an error. But not in case of map. Why?

When you are trying to access the value by the key which is not present in the map, Go will not throw an error, instead, it will return zero value of valueType. The zero value of string is an empty string “ “.

Test that a key is present with a two-value assignment:

elem, ok = m[key]

If key is in m, ok is true. If not, ok is false. If key is not in the map, then elem is the zero value for the map’s element type. The optional second return value when getting a value from a map indicates if the key was present in the map. This can be used to disambiguate between missing keys and keys with zero values like 0 or “”.

package main
import "fmt"
func main() {
	m := make(map[string]int)
        m["score"] = 50
	v, ok := m["score"]
	fmt.Println("The value:", v, "Present?", ok)
}

Output:

The value: 50 Present? true

Question: What is the difference between initialising map using m = make(map[string]string) and m = map[string]string){}? Is one preferred over the another?

One allows you to initialize capacity, one allows you to initialize values:

// Initializes a map with space for 15 items before reallocation
m := make(map[string]string, 15)

Note that this specifies an initial allocation; it can still grow beyond the size specified with the same performance as not using a size.

vs

// Initializes a map with an entry relating the name "bob" to the number 5
m := map[string]int{"bob": 5} 

For an empty map with capacity 0, they’re the same and it’s just preference.

1) If the value is done and if you don’t need to add anything to it before releasing it off into the world, use the {} version 2) If you are planning on adding things to it (usually programmatically) use the make() (or new()) version.

Question: Why does the map m2 is not printed in the following code?

package main

import "fmt"

var m map[string]string
var m2 map[string]string

func main() {
	m = make(map[string]string)
	m["name"] = "Monica"
	fmt.Println(m)
	m1 := map[string]string{}
	m1["name"] = "Ross"
	fmt.Println(m1)
	m2["name"] = "Joey"
	fmt.Println(m2)
}

Output:

map[name:Monica]
map[name:Ross]
panic: assignment to entry in nil map
goroutine 1 [running]:
main.main()
	/tmp/sandbox913434129/prog.go:15 +0x200

Map types are reference types, like pointers or slices, and so the value of m2 above is nil; it doesn’t point to an initialized map. It will not point to anything in memory, so there is nothing to write to.Map cannot hold any data, rather they reference the internal data structure that holds the data.A nil map behaves like an empty map when reading, but attempts to write to a nil map will cause a runtime panic; don’t do that. Initialise maps before writing to it.

Example: Maps are referenced type

package main

import "fmt"

func main() {
	m := map[string]string{
		"Monica": "Geller",
		"Joey":   "Tribbiani",
		"Pheobe": "Buffay",
	}
	mCopy := m
	fmt.Println(m)
	fmt.Println(mCopy)
	delete(m, "Joey")
	fmt.Println(m)
	fmt.Println(mCopy)
}

Output:

map[Joey:Tribbiani Monica:Geller Pheobe:Buffay]
map[Joey:Tribbiani Monica:Geller Pheobe:Buffay]
map[Monica:Geller Pheobe:Buffay]
map[Monica:Geller Pheobe:Buffay]

Like slice, map references an internal data structure. When you copy a map to a new map, the internal data structure is not copied, just referenced.

Question:

Like slice, a map can be only compared with nil.Why can’t we iterate over a map and match each element?

Order of retrieval of elements in map is random when used in for iteration. Hence there is no guarantee that each time, they will be in order. That also explains why we can’t compare two maps. ie checking map1==map2 is not possible

Example: Map Comparison

package main

import "fmt"

func mapEqaulityCheck(a, b map[string]string) bool {
	if len(a) != len(b) {
		return false
	}

	for k, v := range a {
		if w, ok := b[k]; !ok || v != w {
			return false
		}
	}

	return true
}
func main() {
	m := map[string]string{
		"Monica": "Geller",
		"Joey":   "Tribbiani",
		"Pheobe": "Buffay",
	}
	m2 := map[string]string{
		"Pheobe": "Buffay",
		"Monica": "Geller",
		"Joey":   "Tribbiani",
	}

	// invalid operation: m == m2 (map can only be compared to nil)
	// if m == m2 {
	// 	fmt.Println("true")
	// } else {
	// 	fmt.Println("false")
	// }

	check := mapEqaulityCheck(m, m2)
	fmt.Println(check)
}

Output:

true

Tiya Jose ©2019. All rights reserved.

Powered by Hydejack v8.5.1