Go语言中的Map和List实现有序Map

Go语言中的Map和List实现有序Map

Map定义:

Go 中 Map是一种无序的键值对的集合。Map最重要的一点是通过key来快速检索数据,key类似于索引,指向数据的值。Map是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map是无序的,我们无法决定它的返回顺序,这是因为Map是使用链式hash表来实现的。

其他语言中的实现:

在C++ STL 中map 采用红黑树实现,可以实现有序的Map.

在PHP中,Array就是一个有序的map

Go 中实现:

type MapList struct {
    dataMap	map[string]*list.Element
    dataList	*list.List
}

这个实现方法的主要的方法是用空间换取时间。通过list 和 map 两种数据结构,保存相同的一份数据。list 用来做顺序遍历,map 用来做查找,删除操作。

为了把对象保存到 map中,我们还需要定义一个接口

type Keyer interface {
    GetKey() string
}

主要实现代码如下:

package main

import (
	"container/list"
	"fmt"
)

type Keyer interface {
	GetKey() string
}

type MapList struct {
	dataMap  map[string]*list.Element
	dataList *list.List
}

func NewMapList() *MapList {
	return &MapList{
		dataMap:  make(map[string]*list.Element),
		dataList: list.New(),
	}
}

func (mapList *MapList) Exists(data Keyer) bool {
	_, exists := mapList.dataMap[string(data.GetKey())]
	return exists
}

func (mapList *MapList) Push(data Keyer) bool {
	if mapList.Exists(data) {
		return false
	}
	elem := mapList.dataList.PushBack(data)
	mapList.dataMap[data.GetKey()] = elem
	return true
}

func (mapList *MapList) Remove(data Keyer) {
	if !mapList.Exists(data) {
		return
	}
	mapList.dataList.Remove(mapList.dataMap[data.GetKey()])
	delete(mapList.dataMap, data.GetKey())
}

func (mapList *MapList) Size() int {
	return mapList.dataList.Len()
}

func (mapList *MapList) Walk(cb func(data Keyer)) {
	for elem := mapList.dataList.Front(); elem != nil; elem = elem.Next() {
		cb(elem.Value.(Keyer))
	}
}

type Elements struct {
	value string
}

func (e Elements) GetKey() string {
	return e.value
}

func main() {
	fmt.Println("Starting test...")
	ml := NewMapList()
	var a, b, c Keyer
	a = &Elements{"Alice"}
	b = &Elements{"Bob"}
	c = &Elements{"Conrad"}
	ml.Push(a)
	ml.Push(b)
	ml.Push(c)
	cb := func(data Keyer) {
		fmt.Println(ml.dataMap[data.GetKey()].Value.(*Elements).value)
	}
	fmt.Println("Print elements in the order of pushing:")
	ml.Walk(cb)
	fmt.Printf("Size of MapList: %d \n", ml.Size())
	ml.Remove(b)
	fmt.Println("After removing b:")
	ml.Walk(cb)
	fmt.Printf("Size of MapList: %d \n", ml.Size())
}

输出结果:

Starting test...
Print elements in the order of pushing:
Alice
Bob
Conrad
Size of MapList: 3 
After removing b:
Alice
Conrad
Size of MapList: 2 

优点:

红黑树的插入、删除、查找的复杂度都是 O(logn), 而这个实现插入查找删除的复杂度都是 O(1), 可以说是一种非常好的数据结构。

缺点:

使用了两个数据结构,空间占用稍微大了一点。但是和树的实现比,这个占用也不算非常大。

Golangmap换为JSON格式时,默认情况下是无序的。这是因为Golangmap是无序的数据结构,而JSON本身也是一个无序的键值对集合。所以,JSON的参数顺序在大多数情况下对使用没有影响。如果你希望生成有序的JSON数据,可以使用第三方库,例如`encoding/json`包的`MarshalIndent`函数,通过设置`indent`参数来实现按照一定格式生成有序的JSON数据。你可以在代码指定需要的键值对顺序,然后将map换为JSON数据。这样,生成的JSON数据将会按照你指定的顺序进行排列。 示例代码如下: ```go import ( "encoding/json" "fmt" "sort" ) func main() { m := map[string]interface{}{ "key1": "value1", "key3": "value3", "key2": "value2", } keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } sort.Strings(keys) orderedMap := make(map[string]interface{}) for _, k := range keys { orderedMap[k = m[k] } jsonData, err := json.MarshalIndent(orderedMap, "", " ") if err != nil { fmt.Println("Error:", err) return } fmt.Println(string(jsonData)) } ``` 以上示例代码,我们先将map的键取出并排序,然后根据排序后的键重新构建一个有序map。最后使用`json.MarshalIndent`函数将有序map换为有序的JSON数据,并打印输出。这样就能生成按照键的顺序排列的JSON数据了。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [Golang map如何生成有序的json数据详解](https://download.csdn.net/download/weixin_38713039/12872560)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [golang mapjson的顺序问题](https://blog.csdn.net/xz_studying/article/details/103219478)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值