Golang中map的map和带map的结构体该如何选择?

Golang中map的map和带map的结构体该如何选择? 我正在从数据库中提取以下形式的数据: 客户,月份,销售额 ACME公司,01,7500 ABC公司,01,2500 等等… 现在我想要在Go语言中将其添加到合适的载体中。但我不确定最佳的前进方式是什么,是使用结构体还是使用嵌套映射。

到目前为止我尝试了结构体的方式,但我一定是遗漏了什么?

type monthlytotal struct {
    client string
    month map[string]string
}

var months, clients, sales string

for result.Next() {
    err := result.Scan(&months, &clients, &sales)
    if err != nil {
        log.Fatal(err)
    }
    c := new(monthlytotal)
    c.client = clients
    c.month = make(map[string]string)
    c.month[months] = sales
}

这是最佳方式吗?现在如何遍历所有客户并访问映射以打印类似这样的内容?:

ACME 01,7500 ACME 02,7700 等等… ABC公司 01 2500 等等…


更多关于Golang中map的map和带map的结构体该如何选择?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

很高兴能帮上忙 😊

更多关于Golang中map的map和带map的结构体该如何选择?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这个方法立刻奏效了,谢谢!

由于每个客户端都会有多个(月份,销售额)组合,我认为一个比较好的处理方式是使用 map[string][]struct。其中客户端作为键,包含月份和销售额的结构体作为值。(根据我对您问题的理解)

例如:

type monthlytotal struct{
   month string
   sale string
}
.
.
.

var clientMap = make(map[string][]monthlytotal)
var month, client, sale string

for result.Next() {
     err := result.Scan(&month, &client, &sale)
     if err != nil {
        log.Fatal(err)
     }

     var out = monthlytotal{
           month: month,
           sale: sale,
      }
   
      clientMap[client] = append(clientMap[client], out)
} 

for c, outSlice := range clientMap{
   
       for _,  v := range outSlice{
       
            // c 是客户端,v 是切片中的每个元素

            fmt.Println(c, v.month, v.sale)
       }  
}

类似这样的方法应该可行。我有一段时间没接触数据库了,但觉得这个方案应该能满足需求。如果有任何问题请告诉我。

对于你的数据结构需求,使用嵌套映射是更合适的选择。你的结构体方法存在几个问题:每个monthlytotal实例都会覆盖之前的月份数据,而且无法有效存储多个客户的数据。

以下是更优的解决方案:

推荐方案:嵌套映射

// 使用 map[string]map[string]string
// 外层map: 客户 -> 月份映射
// 内层map: 月份 -> 销售额
data := make(map[string]map[string]string)

for result.Next() {
    var client, month, sales string
    err := result.Scan(&client, &month, &sales)
    if err != nil {
        log.Fatal(err)
    }
    
    // 如果客户不存在,创建内层map
    if data[client] == nil {
        data[client] = make(map[string]string)
    }
    
    // 添加月份销售额数据
    data[client][month] = sales
}

遍历和打印数据

// 按客户遍历
for client, monthlyData := range data {
    // 按月份遍历每个客户的数据
    for month, sales := range monthlyData {
        fmt.Printf("%s %s, %s\n", client, month, sales)
    }
}

替代方案:带映射的结构体切片

如果你需要更结构化的方式,可以考虑:

type ClientData struct {
    Name   string
    Sales  map[string]string // 月份 -> 销售额
}

clients := make([]ClientData, 0)
clientMap := make(map[string]int) // 客户名 -> 切片索引

for result.Next() {
    var client, month, sales string
    err := result.Scan(&client, &month, &sales)
    if err != nil {
        log.Fatal(err)
    }
    
    // 检查客户是否已存在
    if idx, exists := clientMap[client]; exists {
        clients[idx].Sales[month] = sales
    } else {
        // 新客户
        newClient := ClientData{
            Name:  client,
            Sales: make(map[string]string),
        }
        newClient.Sales[month] = sales
        clients = append(clients, newClient)
        clientMap[client] = len(clients) - 1
    }
}

// 遍历打印
for _, client := range clients {
    for month, sales := range client.Sales {
        fmt.Printf("%s %s, %s\n", client.Name, month, sales)
    }
}

性能考虑

对于你的用例,简单的嵌套映射方案更简洁高效:

  • 查找时间复杂度:O(1)
  • 内存使用更优
  • 代码更简洁

嵌套映射方案能直接满足你的数据存储和遍历需求,是最佳选择。

回到顶部