77

请看下面我的地图

var romanNumeralDict map[int]string = map[int]string{
  1000: "M",
  900 : "CM",
  500 : "D",
  400 : "CD",
  100 : "C",
  90  : "XC",
  50  : "L",
  40  : "XL",
  10  : "X",
  9   : "IX",
  5   : "V",
  4   : "IV",
  1   : "I",
}

我希望按密钥大小的顺序循环遍历此地图

  for k, v := range romanNumeralDict {
    fmt.Println("k:", k, "v:", v)
  }

但是,这打印出来

k: 1000 v: M
k: 40 v: XL
k: 5 v: V
k: 4 v: IV
k: 900 v: CM
k: 500 v: D
k: 400 v: CD
k: 100 v: C
k: 90 v: XC
k: 50 v: L
k: 10 v: X
k: 9 v: IX
k: 1 v: I

有没有一种方法可以按密钥大小的顺序打印出来,所以我想像这样循环遍历这张地图

k:1
K:4
K:5
K:9
k:10

ETC...

非常感谢您的帮助!

4

5 回答 5

117

收集所有键,对它们进行排序并按键迭代您的地图,如下所示:

keys := make([]int, 0)
for k, _ := range romanNumeralDict {
    keys = append(keys, k)
}
sort.Ints(keys)
for _, k := range keys {
    fmt.Println(k, romanNumeralDict[k])
}
于 2013-08-20T18:51:27.227 回答
38

您可以通过预分配使其更快一点,keys因为您知道它的长度:

func sortedKeys(m map[Key]Value) ([]Key) {
        keys := make([]Key, len(m))
        i := 0
        for k := range m {
            keys[i] = k
            i++
        }
        sort.Keys(keys)
        return keys
}

Keyand替换Value为您的键和值类型(包括sort行)。咳嗽仿制药咳嗽

编辑:Go 1.18 终于有了泛型!这是通用版本:

// Ordered is a type constraint that matches any ordered type.
// An ordered type is one that supports the <, <=, >, and >= operators.
//
// Note the generics proposal suggests this type will be available from
// a standard "constraints" package in future.
type Ordered interface {
    type int, int8, int16, int32, int64,
        uint, uint8, uint16, uint32, uint64, uintptr,
        float32, float64,
        string
}

func sortedKeys[K Ordered, V any](m map[K]V) ([]K) {
        keys := make([]K, len(m))
        i := 0
        for k := range m {
            keys[i] = k
            i++
        }
        sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] })
        return keys
}

游乐场示例

于 2018-06-06T10:08:15.527 回答
1

如果执行速度不是一个大问题,您可以使用MapKeys.

在此示例中,键的类型为string

keys := reflect.ValueOf(myMap).MapKeys()
keysOrder := func(i, j int) bool { return keys[i].Interface().(string) < keys[j].Interface().(string) }
sort.Slice(keys, keysOrder)

// process map in key-sorted order
for _, key := range keys {
    value := myMap[key.Interface().(string)]
    fmt.Println(key, value)
}
  • 请参阅:从地图中获取一部分键
  • 警告:这会绕过一些编译时类型安全(如果不是地图则恐慌)
  • 您需要转换每个键才能获得其原始值:key.Interface().(string)
于 2020-03-28T21:41:05.827 回答
0

根据@Brent 的回答,我有一次想要在一段非关键代码中对映射键进行排序,而不必过多地重复自己。因此,这是为许多不同类型创建通用映射迭代函数的起点:

func sortedMapIteration(m interface{}, f interface{}) {
    // get value and keys
    val := reflect.ValueOf(m)
    keys := val.MapKeys()
    var sortFunc func(i, j int) bool
    kTyp := val.Type().Key()

    // determine which sorting function to use for the keys based on their types.
    switch {
    case kTyp.Kind() == reflect.Int:
        sortFunc = func(i, j int) bool { return keys[i].Int() < keys[j].Int() }
    case kTyp.Kind() == reflect.String:
        sortFunc = func(i, j int) bool { return keys[i].String() < keys[j].String() }
    }
    sort.Slice(keys, sortFunc)

    // get the function and call it for each key.
    fVal := reflect.ValueOf(f)
    for _, key := range keys {
        value := val.MapIndex(key)
        fVal.Call([]reflect.Value{key, value})
    }
}

// example:
func main() {
    sortedMapIteration(map[string]int{
        "009": 9,
        "003": 3,
        "910": 910,
    }, func(s string, v int) {
        fmt.Println(s, v)
    })
}

playground

强调一下:这段代码效率低下并且使用了反射,所以它没有编译时类型安全,一个泛型的实现应该有更多的类型保护和处理更多的关键类型。但是,对于快速而肮脏的脚本,这可以帮助您入门。根据您希望通过的键类型,您将需要向 switch 块添加更多案例。

于 2022-01-21T13:29:40.383 回答
0

您可以通过首先显式对键进行排序来按顺序遍历映射,然后按键遍历映射。由于您从 romanNumeralDict 一开始就知道键的最终大小,因此预先分配所需大小的数组会更有效。

// Slice for specifying the order of the map.
// It is initially empty but has sufficient capacity
// to hold all the keys of the romanNumeralDict map.
keys := make([]int, 0, len(romanNumeralDict))

// Collect keys of the map
i := 0
for k, _ := range romanNumeralDict {
    keys[i] = k
    i++
}

// Ints sorts a slice of ints in increasing order
sort.Ints(keys)

// Iterate over the map by key with an order
for _, k := range keys {
    fmt.Println(k, romanNumeralDict[k])
}
于 2020-08-02T19:23:41.840 回答