golang的map类型介绍及从map到slice和array以及struct nested的转换实例

1,341 阅读6分钟

Golang map examples

这篇文章涵盖了Golang地图类型的教程和实例

在我的上一篇文章中,介绍了Golang中的地图指南。

让我们看看Go语言中地图类型的例子。

如何在Golang中通过键或值对Map进行排序?

map 是一个有序的数据结构,在Golang中具有key-value 对。

我们必须写一个自定义代码来对地图进行排序。

例如,我们有一个字符串key和int values的地图。

打印地图时,返回的地图数据是随机的,而且顺序不被保证。

下面是打印地图的例子

package main  
  
import (  
 "fmt"  
)  
func main() {  
 employees := map[string]int{"Kiran": 2030, "John": 10210,
  "Mark": 25000}  
 fmt.Println(employees)  
 fmt.Println(employees)  
 fmt.Println(employees)  
 fmt.Println(employees)  
 fmt.Println(employees)  
}  

输出是

map[John:10210 Mark:25000 Kiran:2030]  
map[John:10210 Mark:25000 Kiran:2030]  
map[Kiran:2030 John:10210 Mark:25000]  
map[Mark:25000 Kiran:2030 John:10210]  
map[Kiran:2030 John:10210 Mark:25000]  

现在,你如何根据键值对地图进行排序?

package main  
  
import (  
 "fmt"  
 "sort"  
)  
  
func main() {  
 employees := map[string]int{"Kiran": 2030, "John": 10210, "Mark": 25000}  
 fmt.Println(employees)  
  
 keys := make([]string, 0, len(employees))  
 for k := range employees {  
  keys = append(keys, k)  
 }  
 sort.Strings(keys)  
 for _, k := range keys {  
  fmt.Println(k, employees[k])  
 }  
}  

显示的地图是按键值排序的,输出是

map[Mark:25000 Kiran:2030 John:10210]  
John 10210  
Kiran 2030  
Mark 

如何用一个数组创建一个嵌套的地图类型

在这个例子中,你可以创建一个Map,key是字符串,value是地图数组。首先,使用literal语法的功能创建一个带有数组地图的Map。

 mapArraysMap := map[string][]map[string]string{  
  "kiran": {{"id": "1"}, {"name": "kiran"}},  
  "john":  {{"id": "2"}, {"name": "kiran"}},  
 }

它创建了一个Map ,其中key 是一个字符串,分配给一个数组地图的值。添加和删除元素的方式与普通地图相同。

下面是一个Map与数组地图的完整例子

package main  
  
import (  
 "fmt"  
)  
  
func main() {  
  
 //Create a Map with array of map  
 mapArraysMap := map[string][]map[string]string{  
  "kiran": {{"id": "1"}, {"name": "kiran"}},  
  "john":  {{"id": "2"}, {"name": "kiran"}},  
 }  
 fmt.Println(mapArraysMap)  
 fmt.Println("Original length: ", len(mapArraysMap))  
 //Adding an Array of Map values to map  
 mapArraysMap["frank"] = []map[string]string{{"id": "2"}, {"name": "kiran"}}  
 fmt.Println(mapArraysMap)  
 fmt.Println("length: ", len(mapArraysMap))  
 //Delete entry from Map  
 delete(mapArraysMap, "frank")  
 fmt.Println("length: ", len(mapArraysMap))  
  
}

输出:

map[3:Gef 1:ram 2:arun]  
map[kiran:[map[id:1] map[name:kiran]] john:[map[id:2] map[name:kiran]]]  
Original length:  2  
map[john:[map[id:2] map[name:kiran]] frank:[map[id:2] map[name:kiran]] kiran:[map[id:1] map[name:kiran]]]  
length:  3  
length:  2  

如何从Map转换Slice/Array?

Slice 是一个动态数组,其长度在运行时增长。map 是一个具有键和值对的集合。

map 在搜索、添加和删除方面的性能很好,但在迭代方面却不好。有时,我们需要将一个Slice的字符串转换为MAP。然而,没有标准的API函数可以将Slice字符串转换为Map。

声明并初始化了一个slice ,其中有如下的字符串字样

//create a slice with string literal  
countries := []string{"india", "USA", "UK", "France"}  

同时创建一个Map ,键为整数,值为字符串。用简单的for循环或带范围的循环来迭代slice

下面是一个完整的例子

package main  
  
import (  
 "fmt"  
)  
  
func main() {  
  
 //create a slice with string literal  
 countries := []string{"india", "USA", "UK", "France"}  
 fmt.Println(countries)  
 // Create and initilize a Map with make function  
 countriesMap := make(map[int]string)  
 // Iterate Slice  
 for i := 0; i < len(countries); i++ {  
  countriesMap[i] = countries[i]  
 }  
 fmt.Println(countriesMap)  
}  

输出:

[india USA UK France]  
map[2:UK 3:France 0:india 1:USA]  

由于Map 是一个无序的数据结构,当你多次运行上述程序时,显示数据的顺序可能会改变。

如何将地图转换为数组的键/值/项片?

通常,我们需要从一个Map 类型中检索键、值或两者。
例如,我们有一个Map ,其中的键和值是字符串类型。
下面的程序讲述了以下内容:

  • 从Map中获取键的片断。
  • 来自Map的值的数组。
  • 从Map中获取项目的键值切片。

下面是Convert Map to Key/values/items Slices example 的代码。

package main  
  
import (  
 "fmt"  
)  
  
func main() {  
 // Create and intilize map with string literals - First Name - Last Name  
 names := map[string]string{  
  "kiran":  "Babu",  
  "John":   "Frank",  
  "Silver": "Stallin",  
 }  
 fmt.Println("Map   ", names)  
 fmt.Println("Key value ", names)  
  
 // Retrieve keys of slice from Map  
 keys := []string{}  
 for key, _ := range names {  
  keys = append(keys, key)  
 }  
 fmt.Println("Keys  ", keys)  
  
 // Retrieve values of slice from Map  
 values := []string{}  
 for _, value := range names {  
  values = append(values, value)  
 }  
 fmt.Println("Values ", values)  
  
 // Retrieve  slice of key-value pairs from Map  
 items := [][]string{}  
 for key, value := range names {  
  items = append(items, []string{key, value})  
 }  
 fmt.Println("Values ", items)  
  
}  

输出:

Map    map[kiran:Babu John:Frank Silver:Stallin]  
Key value  map[Silver:Stallin kiran:Babu John:Frank]  
Keys   [Silver kiran John]  
Values  [Frank Stallin Babu]  
Values  [[Silver Stallin] [kiran Babu] [John Frank]]  

将两个或多个地图合并成一个地图

在Golang中没有标准的函数用于mergejoin 地图。我们必须写一个自定义函数来将多个地图merge 为一个单一的地图。

结果地图对于一个给定的键可能有多个值,所以值应该被声明为slice ,然后输出map[string][]string类型的地图。

下面是地图合并的过程

  • 迭代地图
  • 对于每一次迭代,将源地图中的每个值追加到输出地图中给定键的分片上
  • 一旦分片地图被追加,我们必须把这个分片分配给输出地图的给定键值
  • 这个过程允许输出地图中出现重复的元素

下面是一个完整的地图合并的例子

package main  
  
import (  
 "fmt"  
)  
  
func main() {  
 m1 := map[string]string{"k1": "v1"}  
 m2 := map[string]string{"k2": "v2"}  
 m3 := map[string]string{"k1": "v3"}  
  
 output := mergeMaps(m1, m2, m3)  
 fmt.Println(output)  
  
}  
func mergeMaps(maps ...map[string]string) map[string][]string {  
 result := map[string][]string{}  
 for _, m := range maps {  
  for k, v := range m {  
   result[k] = append(result[k], v)  
  }  
 }  
 return res  
}  

上述程序的输出

map[id_1:[val_1 val_3] id_2:[val_2]]  

如何检查地图的键和值的类型 - Reflection API

我们可以使用标准反射API获得地图的键和值的类型。

reflect.TypeOf() function返回给定变量的动态类型。如果给定的变量是nil 接口,它将返回nil

reflect.TypeOf().key() function 返回地图键的数据类型。如果给定的类型不是 ,它会抛出一个紧急错误。map

reflect.TypeOf().elem() function 返回地图值的数据类型。如果给定的类型不是 ,它会抛出一个恐慌性错误。map

下面是一个完整的例子

package main  
  
import (  
 "fmt"  
 "reflect"  
)  
  
func main() {  
  
 var mymap map[string]int  
 fmt.Println("Map Type: ", reflect.TypeOf(mymap))  
 fmt.Println("Map Key Type: ", reflect.TypeOf(mymap).Key())  
 fmt.Println("Map Value Type: ", reflect.TypeOf(mymap).Elem())  
  
 mapArraysMap := map[string][]map[string]string{  
  "kiran": {{"id": "1"}, {"name": "kiran"}},  
 }  
 fmt.Println("Map Type: ", reflect.TypeOf(mapArraysMap))  
 fmt.Println("Map Key Type: ", reflect.TypeOf(mapArraysMap).Key())  
 fmt.Println("Map Value Type: ", reflect.TypeOf(mapArraysMap).Elem())  
  
}  

输出:

Map Type:  map[string]int  
Map Key Type:  string  
Map Value Type:  int  
Map Type:  map[string][]map[string]string  
Map Key Type:  string  
Map Value Type:  []map[string]string  

将Struct类型与Map转换为JSON类型

在下面给定的代码中,我们已经声明了一个struct ,其中有标准字符串对象的每个元素,除了地址元素。地址元素是一个map 的字符串。

type Employee struct {  
 Id      string            `json:"id,omitempty"`  
 Name    string            `json:"name,omitempty"`  
 Address map[string]string `json:"address,omitempty"`  
}  

将使用j将这个struct 转换为JSONson.MarshalIndent() function

以下是一个例子

package main  
  
import (  
 "encoding/json"  
 "fmt"  
)  
  
// Declare Struct type  
type Employee struct {  
 Id      string            `json:"id,omitempty"`  
 Name    string            `json:"name,omitempty"`  
 Address map[string]string `json:"address,omitempty"`  
}  
  
func main() {  
 // Initialized Struct and add data to it  
 var emp Employee  
 emp.Id = "1"  
 emp.Name = "Frank"  
 m := make(map[string]string)  
 emp.Address = m  
 emp.Address["city"] = "Newyork"  
 emp.Address["country"] = "USA"  
 emp.Address["zipcode"] = "92451"  
  
 var data []byte  
 // Convert struct to json  
 data, _ = json.MarshalIndent(emp, "", "    ")  
  
 fmt.Println(string(data))  
}  

输出:

{  
    "id": "1",  
    "name": "Frank",  
    "address": {  
        "Country": "USA",  
        "city": "Newyork",  
        "zipcode": "92451"  
    }  
}  

总结

在这篇文章中,你学习了golang的地图类型,有多个例子,以及从地图到slice和array以及struct nested的转换。