// HASHTABLES
// Hashtables contain key/value pairs
// Key must be unique (Arbitrary, must be hashable by the hash function though)
// Hash function is used to compute a slot for a key
// This goes on behind the scenes when you want to insert
// a value for a particular key.
// There can be collosions in a Hashtable, that occurs when two keys hash to the same
// slot. There are strategies to handle those collisions like putting them in a list and tracking them...
// When you get a collision  like this your access and insert are a little slower.
// Allows for access in constant O(1) time. Lists are linear O(N) time for a lookup.

// MAPS
// GOLangs specific implementation of a Hashtable
// can use make function to create a map.

package main

import "fmt"

// map declaration
var myMap map[string]int

func main() {
	// Using make
	m2 := make(map[string]int)
	fmt.Println(m2)
	// map literal
	m3 := map[string]int{"Drew": 1337, "Margot": 9000}
	fmt.Println(m3, len(m3))
	fmt.Printf("Margot's power level: %d\n", m3["Margot"])
	m3["Laura"] = 100_000 // like python you can use _ to see places
	fmt.Println(m3, len(m3))
	// delete value from map
	delete(m3, "Drew")
	fmt.Println(m3, len(m3))

	// Two value assignment
	// p will be a boolean if the key is in the map
	val, p := m3["Margot"]
	if p {
		fmt.Println("Found key Margot in map with value: ", val)
	} else {
		fmt.Println("Key Margot not present in map. Got back: ", val)
	}

	val, p = m3["Drew"]
	if p {
		fmt.Println("Found key Drew in map with value: ", val)
	} else {
		fmt.Println("Key Drew not present in map. Got back: ", val)
	}

	// iterating through a map
	for key, value := range m3 {
		fmt.Printf("Key: %s, Value: %d\n", key, value)
	}

}