我们在日常开发中,或多或少会经常需要对
map
进行排序,这里就带大家实现对map
排序的封装
- 调用简单,使用方便
- 支持对
int
int8
int16
int32
int64
float64
float32
string
作为key
的map
进行排序遍历
思路
通常我们对
map
进行排序都是先将key
存储到一个slice
中,之后对其进行排序操作,但是封装起来会遇到以各种类型作为key
和value
的map
,这种情况我们按照如下方法来克服
- 声明一个拥有两个入参的函数,用来完成我们的操作,即
func EachMap(eachMap interface{}, eachFunc interface{})
- eachMap :传入
map
,因为是interface{}
,所以只要是map都能够传入- eachFunc :接收
map
的key
和value
的函数,需要包含两个入参,类型要与map
的key
和value
完全一致
- 最后利用golang的反射就可以完成这个功能。
代码如下
源码地址:https://gitee.com/xusixxxx/bug-research-laboratory/tree/master/kercylan-core/utils/ksort
// 以map的key(int\float\string)排序遍历map
// eachMap -> 待遍历的map
// eachFunc -> map遍历接收,入参应该符合map的key和value
// 需要对传入类型进行检查,不符合则直接panic提醒进行代码调整
func EachMap(eachMap interface{}, eachFunc interface{}) {
eachMapValue := reflect.ValueOf(eachMap)
eachFuncValue := reflect.ValueOf(eachFunc)
eachMapType := eachMapValue.Type()
eachFuncType := eachFuncValue.Type()
if eachMapValue.Kind() != reflect.Map {
panic(errors.New("ksort.EachMap failed. parameter \"eachMap\" type must is map[...]...{}"))
}
if eachFuncValue.Kind() != reflect.Func {
panic(errors.New("ksort.EachMap failed. parameter \"eachFunc\" type must is func(key ..., value ...)"))
}
if eachFuncType.NumIn() != 2 {
panic(errors.New("ksort.EachMap failed. \"eachFunc\" input parameter count must is 2"))
}
if eachFuncType.In(0).Kind() != eachMapType.Key().Kind() {
panic(errors.New("ksort.EachMap failed. \"eachFunc\" input parameter 1 type not equal of \"eachMap\" key"))
}
if eachFuncType.In(1).Kind() != eachMapType.Elem().Kind() {
panic(errors.New("ksort.EachMap failed. \"eachFunc\" input parameter 2 type not equal of \"eachMap\" value"))
}
// 对key进行排序
// 获取排序后map的key和value,作为参数调用eachFunc即可
switch eachMapType.Key().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
keys := make([]int, 0)
keysMap := map[int]reflect.Value{}
for _, value := range eachMapValue.MapKeys() {
keys = append(keys, int(value.Int()))
keysMap[int(value.Int())] = value
}
sort.Ints(keys)
for _, key := range keys {
eachFuncValue.Call([]reflect.Value{keysMap[key], eachMapValue.MapIndex(keysMap[key])})
}
case reflect.Float64, reflect.Float32:
keys := make([]float64, 0)
keysMap := map[float64]reflect.Value{}
for _, value := range eachMapValue.MapKeys() {
keys = append(keys, float64(value.Float()))
keysMap[float64(value.Float())] = value
}
sort.Float64s(keys)
for _, key := range keys {
eachFuncValue.Call([]reflect.Value{keysMap[key], eachMapValue.MapIndex(keysMap[key])})
}
case reflect.String:
keys := make([]string, 0)
keysMap := map[string]reflect.Value{}
for _, value := range eachMapValue.MapKeys() {
keys = append(keys, value.String())
keysMap[value.String()] = value
}
sort.Strings(keys)
for _, key := range keys {
eachFuncValue.Call([]reflect.Value{keysMap[key], eachMapValue.MapIndex(keysMap[key])})
}
default:
panic(errors.New("\"eachMap\" key type must is int or float or string"))
}
}
使用
func main() {
m := map[int]string{}
m[5] = "Hello World"
m[2] = "Hello World"
m[1] = "Hello World"
m[3] = "Hello World"
m[4] = "Hello World"
EachMap(m, func(key int, value string) {
fmt.Println(key, value)
})
}