Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write a bidirectional mapping in Go?

Tags:

mapping

go

I am writing a simple console game and would like to map a player to a symbol. With two players my approach looks like this:

func playerToString(p player) string {
    if p == 0 {
        return "X"
    }
    return "O"
}

func stringToPlayer(s string) player {
    if s == "X" {
        return 0
    }
    return 1
}

Of cause you could also write this as two maps mapping int to string and string to int. Both the above approach and the map approach seem error-prone. Is there a more idiomatic way to write this in go? Maybe some non-iota enum way?

like image 398
User12547645 Avatar asked Oct 28 '25 07:10

User12547645


2 Answers

[I assume your example is just minimal and that your actual mapping has more than two options. I also assume you meant bi-directonal mapping]

I would write one map:

var player2string = map[int]string{
  0: "0",
  1: "X",
  // etc...
}

And then would create a function to populate a different map string2player programmatically. Something like this:

var player2string = map[int]string{
    0: "0",
    1: "X",
    // etc...
}

var string2player map[string]int = convertMap(player2string)

func convertMap(m map[int]string) map[string]int {
    inv := make(map[string]int)
    for k, v := range m {
        inv[v] = k
    }
    return inv

}

func main() {
    fmt.Println(player2string)
    fmt.Println(string2player)
}

Try it on the Go playground

like image 180
Eli Bendersky Avatar answered Oct 31 '25 08:10

Eli Bendersky


In addition to Eli's answer, two other changes you could make. You could make the to-symbol function a method of the player type. And because the player values are integers (sequential starting from zero), you can use a slice instead of a map to store the int-to-symbol mapping -- it's a bit more efficient to store and for lookup.

type player int

var playerSymbols = []string{"X", "O", "A", "B", "C", "D", "E", "F", "G", "H"}

func (p player) Symbol() string {
    if int(p) < 0 || int(p) >= len(playerSymbols) {
        return "?" // or panic?
    }
    return playerSymbols[p]
}

This method signature could even be String() string so it's a fmt.Stringer, which can be useful for printing stuff out and debugging.

like image 34
Ben Hoyt Avatar answered Oct 31 '25 06:10

Ben Hoyt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!