# 23. Maps

### Map Type

Map is collection of key value pairs. It goes by various names in other programming languages like dictionaries in Python, objects in JavaScript etc.

Maps are represented as  `map[K]V`, where `K` and `V` are the types of its keys and values.

### Declaring Maps

We can declare `map` using var declaration. We are defining `string` to be keys for the map and `string` to be values. Since map is declared but not initialized with any value, it will be a `nil` map.&#x20;

{% code title="main.go" %}

```go
var capitals map[string]string
fmt.Println(capitals)
fmt.Println("is map nil ==>", capitals == nil)
```

{% endcode %}

### Creating map

Maps are created using `make` function call. `make` will perform the required memory allocation required to use map. We can add elements to map using `map[key] = value` semantics.&#x20;

{% code title="main.go" %}

```go
caps := make(map[string]string)
// we can also use var keyword as below
// var caps map[string]string = make(map[string]string)
fmt.Println(caps)
fmt.Println("is map nil ==>", caps == nil) 
// returns false
caps["India"] = "Delhi"
caps["England"] = "London"
caps["U.S."] = "Washington"
fmt.Println(caps)
```

{% endcode %}

### Map Literals

We can also use map literal to declare and initialize maps. `make` function call is not required when using map literal.

{% code title="main.go" %}

```go
capitalsOfCountries := map[string]string{
    "India":   "Delhi",
    "England": "London",
    "U.S.":    "Washington",
}
fmt.Println(capitalsOfCountries)
```

{% endcode %}

### Accessing map elements

map elements can be accessed using subscript notion similar to array and slices. In array and slices, index can only be integers. For maps, however, key can be anything which can be compared using `==` comparison.

{% code title="main.go" %}

```go
//accessing map elements
fmt.Println(capitalsOfCountries["India"])
fmt.Println(capitalsOfCountries["England"])
```

{% endcode %}

If we try to access map key which does not exists, it will not cause an error, but will return zero value.

{% code title="main.go" %}

```go
fmt.Println(capitalsOfCountries["XYZ"]) 
// prints empty string
```

{% endcode %}

### Zero values for map

Zero value for map is nil. Zero value for map element is zero value for type being stored as value.

{% code title="main.go" %}

```go
var s map[string]string
var i map[string]int
fmt.Println("is s nil =>", s == nil)
fmt.Println("is i nil =>", i == nil)
```

{% endcode %}

If map is not nil, but empty, accessing its elements will returns its zero value.

{% code title="main.go" %}

```go
// zero value for map elements
j := map[string]int{}
fmt.Println(j["India"]) // output : 0

```

{% endcode %}

Notice that, event if key does to exist in empty map, it did return zero value.

### Nil and empty map

Similar to slices, maps can be empty or nil. When we use make function call or use map literal for declaring map, it initializes empty map

{% code title="main.go" %}

```go
var t = make(map[string]string)
k := map[string]int{}
fmt.Println("is t nil =>", t== nil)
fmt.Println("is k nil =>", k== nil)
```

{% endcode %}

Both `nil` and empty maps have `len()` as zero.

{% code title="main.go" %}

```go
var s map[string]string
var t = make(map[string]string)
fmt.Println(len(s))
fmt.Println(len(t))
```

{% endcode %}

### Iterating over map

Iterating over maps is similar to array and slices, we can use `for...range` loop for iteration. `range` works as follows for a map

`for key,value :=range map { // }`

{% code title="main.go" %}

```go
for key, value := range caps {
	fmt.Printf("key =>%v, value => %v\n", key, value)
}
```

{% endcode %}

{% hint style="danger" %}
Unlike arrays and slices, maps do not guarantee same order. Map is unordered collection of key-value pairs.
{% endhint %}

If either key or value is not required, we can omit it by using blank identifier.

{% code title="main.go" %}

```go
for _, value := range caps {
	fmt.Printf("value => %v\n", value)
}
for key, _ := range caps {
	fmt.Printf("key =>%v\n", key)
}
```

{% endcode %}

### Finding element in map

To find element in map, we provide key to the map to get element/value returned from map. A map does not panic if we try to access key which is not present, instead it returns zero value. To identify if value is returned is actual value present on map or zero value returned due to absence of key, map returns a second value, `ok` which tells if key was found or not. &#x20;

If we see output for below code snippet, when we check for `XYZ` and `ABC`, both returns empty string. For `XYZ`, value is empty string, while for `ABC`, it is missing from map.

{% code title="main.go" %}

```go
cocs := map[string]string{
		"India":   "Delhi",
		"England": "London",
		"U.S.":    "Washington",
		"XYZ":     "",
	}

fmt.Printf("Checking captial for India-> %v\n",
	cocs["India"])
fmt.Printf("Checking captial for XYZ-> %v\n",
	cocs["XYZ"])
fmt.Printf("Checking captial for ABC-> %v\n",
	cocs["ABC"])
```

{% endcode %}

To distinguish between empty/zero value and missing value, we can use `value,ok` semantics.

{% code title="main.go" %}

```go
value, ok := cocs["XYZ"]
if ok {
	fmt.Printf("Value is %v \n", value)
} else {
	fmt.Println("Key not found")
}
value, ok = cocs["ABC"]
if ok {
	fmt.Printf("Value is %v \n", value)
} else {
	fmt.Println("Key not found")
}
```

{% endcode %}

### Updating element in map

Updating value is similar to creating a value. We can use&#x20;

`map[key]= value` semantic to update value for given key.

{% code title="main.go" %}

```go
capitals = map[string]string{
		"India":   "",
		"England": "London",
		"U.S.":    "Washington",
}
capitals["India"] = "Delhi"
fmt.Println(capitals)
```

{% endcode %}

### Deleting element from map

Deleting value from map is straightforward. Go provides inbuilt delete function to delete a value from map. Semantics for delete is&#x20;

`delete(mapName,key)`

{% code title="main.go" %}

```go
capitals = map[string]string{
		"India":   "Pune",
		"England": "London",
		"U.S.":    "Washington",
}

delete(capitals, "England")
fmt.Println(capitals)
```

{% endcode %}

### Comparing maps

Similar to slices, maps can not be compared directly. We can only check if a map is nil or not directly. For other comparisons, we need to write our own for loop for comparison.

### GitHub Code

{% embed url="<https://github.com/gophersumit/codewithgo-samples/tree/master/maps>" %}

### Blog Posts

{% embed url="<https://blog.golang.org/go-maps-in-action>" %}

{% embed url="<https://www.ardanlabs.com/blog/2013/12/macro-view-of-map-internals-in-go.html>" %}

### Videos

{% embed url="<https://www.youtube.com/watch?v=Tl7mi9QmLns>" %}
GopherCon 2016: Keith Randall - Inside the Map Implementation
{% endembed %}
