目录

  • Map声明
  • Map添加元素
  • Map删除元素
  • Map元素访问
  • Map遍历
  • Map排序
  • 如何按Key排序Map
  • 如何按Value排序Map

Map声明

  • 声明后添加元素
m := map[string]int{}
m["a"] = 1
  • 声明并初始化
m := map[string]int{"a":1, "b":2, "c":3}
  • make创建
m := make(map[string]int, 10/*Initial Capacity*/)

上一篇文章我们使用make创建了切片,同样make也可以创建Map,不同的是不需要初始化len,原因是Map无法设置元素默认值,而切片可以根据数据的类型设置默认值,比如切片的元素为int类型,默认值则为0.

使用make通过预先设置capacity的方式创建,避免了capacity在自增的过程的分配新的内存空间和内存拷贝,可以减少内存消耗,提高性能。

接下来我代码演示下Map的创建:

func TestInitMap(t *testing.T) {
	m1 := map[int]int{1: 1, 2: 2, 3: 3}
	t.Log(m1, len(m1))

	m2 := map[int]int{}
	t.Log(m2, len(m2))
	m2[0] = 0
	m2[5] = 5
	t.Log(m2, len(m2))

	m3 := make(map[string]string, 10)
	// 不能查看Map的Capacity,否者会报错:Invalid argument for cap
	//t.Log(m3, len(m3), cap(m3))
	t.Log(m3, len(m3))
	m3["a"] = "1"
	m3["b"] = "2"
	m3["c"] = "3"
	m3["d"] = "4"
	t.Log(m3, len(m3))
}

Map添加元素

m[Key] = Value

Map删除元素

delete(m, Key)

例如:

func TestDeleteKey(t *testing.T) {
	m := map[int]int{}
	t.Log(m[1])
	m[2] = 0
	t.Log(m[2])
	printKey3Exists(&m, t)
	m[3] = 0
	printKey3Exists(&m, t)
	delete(m, 3)
	printKey3Exists(&m, t)
}

func printKey3Exists(m *map[int]int, t *testing.T) {
	t.Log(m)

	if v, ok := (*m)[3]; ok {
		t.Logf("key 3's value is %d", v)
	} else {
		t.Log("key 3 is not existing.")
	}
}

Map元素访问

Map元素的访问其实和其他编程语言没什么区别,都是通过Key来得到Value。

t.Log(m3["d"])

不同的是,当访问一个不存在的Key时,Value为类型的默认值,这样虽然可以避免在取一个不存在的Key时,不会出现异常,但是不能知道这个Key到底存不存在。
Go当然考虑到了这一点,即使用10《Go语言入门》循环和条件中讲过的条件语句特殊写法来实现Key是否存在的判断。

func TestAccessNotExistingKey(t *testing.T) {
	m1 := map[int]int{}
	t.Log(m1[0]) // 0这个key不存在,取int的默认值0为value
	m1[2] = 0
	t.Log(m1[2])

	m2 := map[string]string{}
	t.Log(m2["a"]) // a这个key不存在,取string的默认值空字符串为value
	m2["a"] = "1"
	t.Log(m2["a"])

	// 这样虽然可以避免在取一个不存在的key时,不会出现异常,但是不能知道这个key到底存不存在
	key := 3
	m1[key] = 31
	if v, exists := m1[3]; exists {
		t.Logf("Key %d's value is %d", key, v)
	} else {
		t.Logf("Key %d is not existing", key)
	}
}

Map遍历

和数组、切片的遍历是一样的。
这里我们随便回忆下数组和切片的遍历。
需要注意的是:map底成是通过hash来指定存储位置的,所以遍历出来的元素不是有序的。

func TestTravelMap(t *testing.T) {
	t.Log("Map遍历")
	m3 := make(map[string]string, 10)
	t.Log(reflect.TypeOf(m3))
	m3["a"] = "1"
	m3["b"] = "2"
	m3["c"] = "3"
	m3["d"] = "4"
	t.Log(m3)
	for key, value := range m3 {
		t.Log(key, value)
	}

	t.Log("Array遍历")
	array := [...]string{"a", "b", "c"}
	t.Log(reflect.TypeOf(array))
	for index, element := range array {
		t.Log(index, element)
	}

	t.Log("Slice遍历")
	slice := []string{"a", "b", "c"}
	t.Log(reflect.TypeOf(slice))
	for index, element := range slice {
		t.Log(index, element)
	}
}

Map排序

如何按Key排序Map

我这里写一种方法,通过将Key存储到slice中,然后给slice排序,再遍历slice即可。

func TestSortByKey(t *testing.T) {
	m1 := map[string]int{"aa": 1, "zz": 2, "bb": 3, "yy": 4, "cc": 5, "xx": 6}
	s1 := make([]string, 0, len(m1))
	for k, _ := range m1 {
		s1 = append(s1, k)
	}
	sort.Strings(s1)
	for _, k := range s1 {
		t.Log(k, m1[k])
	}
}

如何按Value排序Map

很容易理解的,直接看代码吧。

func TestSortByValue(t *testing.T) {
	m1 := map[string]int{"aa": 3, "zz": 1, "bb": 5, "yy": 2, "cc": 4, "xx": 6}
	valueSlice := make([]int, 0, len(m1))
	for _, value := range m1 {
		valueSlice = append(valueSlice, value)
	}
	sort.Ints(valueSlice)
	for _, element := range valueSlice {
		for key, value := range m1 {
			if element == value {
				t.Log(key, value)
			}
		}
	}
}