Sort Go map values by keys

后端 未结 6 621
悲哀的现实
悲哀的现实 2020-11-28 02:58

When iterating through the returned map in the code, returned by the topic function, the keys are not appearing in order.

How can I get the keys to be in order / sor

6条回答
  •  刺人心
    刺人心 (楼主)
    2020-11-28 03:30

    If, like me, you find you want essentially the same sorting code in more than one place, or just want to keep the code complexity down, you can abstract away the sorting itself to a separate function, to which you pass the function that does the actual work you want (which would be different at each call site, of course).

    Given a map with key type K and value type V, represented as and below, the common sort function might look something like this Go-code template (which Go version 1 does not support as-is):

    /* Go apparently doesn't support/allow 'interface{}' as the value (or
    /* key) of a map such that any arbitrary type can be substituted at
    /* run time, so several of these nearly-identical functions might be
    /* needed for different key/value type combinations. */
    func sortedMap(m map[], f func(k , v )) {
        var keys []
        for k, _ := range m {
            keys = append(keys, k)
        }
        sort.Strings(keys)  # or sort.Ints(keys), sort.Sort(...), etc., per 
        for _, k := range keys {
            v := m[k]
            f(k, v)
        }
    }
    

    Then call it with the input map and a function (taking (k , v ) as its input arguments) that is called over the map elements in sorted-key order.

    So, a version of the code in the answer posted by Mingu might look like:

    package main
    
    import (
        "fmt"
        "sort"
    )
    
    func sortedMapIntString(m map[int]string, f func(k int, v string)) {
        var keys []int
        for k, _ := range m {
            keys = append(keys, k)
        }
        sort.Ints(keys)
        for _, k := range keys {
            f(k, m[k])
        }
    }
    
    func main() {
        // Create a map for processing
        m := make(map[int]string)
        m[1] = "a"
        m[2] = "c"
        m[0] = "b"
    
        sortedMapIntString(m,
            func(k int, v string) { fmt.Println("Key:", k, "Value:", v) })
    }
    

    The sortedMapIntString() function can be re-used for any map[int]string (assuming the same sort order is desired), keeping each use to just two lines of code.

    Downsides include:

    • It's harder to read for people unaccustomed to using functions as first-class
    • It might be slower (I haven't done performance comparisons)

    Other languages have various solutions:

    • If the use of and (to denote types for the key and value) looks a bit familiar, that code template is not terribly unlike C++ templates.
    • Clojure and other languages support sorted maps as fundamental data types.
    • While I don't know of any way Go makes range a first-class type such that it could be substituted with a custom ordered-range (in place of range in the original code), I think some other languages provide iterators that are powerful enough to accomplish the same thing.

提交回复
热议问题