Search code examples
algorithmsortingdictionarygohashmap

How do I sort a map in Go based on another map's key values?


I need to sort a map based on the keys of another map because my current function that returns a map is not sorted so I need it to be consistent based on this order of names, as seen in reference. I am aware of some of the sort functions, however, I am having some trouble implementing them. To reiterate, I need the names to be sorted the same way as the reference variable; no alphabetical order just based on one specific map ordering. It would be great if someone could please help with this.

To clarify, I need to sort the returned values from testMap() and testMap2() based on the same order as reference. The reference variable shows the connection between the two names (the difference in naming conventions).

package main

import (
    "fmt"
)

var reference = map[string]string{"Ali": "Ali_1", "Cat": "Cat1", "Bob": "Bob"}

func main() {
    testMap() 
}

func testMap() map[string]int {
    return map[string]int{"Ali_1": 2, "Bob": 3, "Cat1": 3} // goal is to sort this in the same order of keys(names) as the reference variable
}

func testMap2() map[string]int {
    return map[string]int{"Ali": 2, "Bob": 3, "Cat": 3} // goal is to sort this in the same order of keys(names) as the reference variable
}

Solution

  • Preliminary note

    To reiterate something important from the comments: maps in Go do not have defined orders and you therefore cannot sort them or guarantee their order.

    From Go maps in action:

    When iterating over a map with a range loop, the iteration order is not specified and is not guaranteed to be the same from one iteration to the next. If you require a stable iteration order you must maintain a separate data structure that specifies that order.


    Answer

    You can iterate over the keys/values in reference and get the value from the first and second map using the first and second key.

    package main
    
    import (
        "fmt"
    )
    
    var reference = map[string]string{"Ali": "Ali_1", "Cat": "Cat1", "Bob": "Bob"}
    
    func main() {
        m1 := testMap()
        m2 := testMap2()
    
        for key1, key2 := range reference {
            v1, _ := m1[key1]
            v2, _ := m2[key2]
            fmt.Printf("%s/%s: (%d, %d)\n", key1, key2, v1, v2)
            // not sure what you want with these, so I'm just printing
        }
    }
    
    func testMap() map[string]int {
        return map[string]int{"Ali_1": 2, "Bob": 3, "Cat1": 3} // goal is to sort this in the same order of keys(names) as the reference variable
    }
    
    func testMap2() map[string]int {
        return map[string]int{"Ali": 2, "Bob": 3, "Cat": 3} // goal is to sort this in the same order of keys(names) as the reference variable
    }
    
    

    Note that this still does not guarantee order, only that the values for the "matching" keys are paired up.

    If you want order you'll need something that has order (e.g. a slice). For example:

    package main
    
    import (
        "fmt"
    )
    
    var keyOrder = []string{"Ali", "Cat", "Bob"}
    var reference = map[string]string{"Ali": "Ali_1", "Cat": "Cat1", "Bob": "Bob"}
    
    func main() {
        m1 := testMap()
        m2 := testMap2()
    
        for _, key1 := range keyOrder {
            key2, _ := reference[key1]
            v1, _ := m1[key1]
            v2, _ := m2[key2]
            fmt.Printf("%s/%s: (%d, %d)\n", key1, key2, v1, v2)
        }
    }
    
    func testMap() map[string]int {
        return map[string]int{"Ali_1": 2, "Bob": 3, "Cat1": 3} // goal is to sort this in the same order of keys(names) as the reference variable
    }
    
    func testMap2() map[string]int {
        return map[string]int{"Ali": 2, "Bob": 3, "Cat": 3} // goal is to sort this in the same order of keys(names) as the reference variable
    }
    

    or you can change reference to look something like this:

    var reference = [][]string{{"Ali", "Ali_1"}, {"Cat", "Cat1"}, {"Bob", "Bob"}}
    

    (Which would be more flexible if you have more than two maps involved, but you have to make sure the order in the subslices matches the map order.)

    Though this is getting more hacked together as we progress. You might consider a different approach altogether, maybe using more complex types like structs or something. Or take a step back and consider why you have these mismatched keys in the first place.