Reputation: 8507
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?
Upvotes: 4
Views: 2925
Reputation: 1
For anyone that finds this thread down the line I wanted a more ergonomic solution for bi-directional value mapping so I created a small module to do this. If anyone is looking for a ready made solution.
https://github.com/graytonio/go-bidirectional-map
myMap := bidmap.NewMap(map[string]int{
"foo": 3,
"bar": 4,
})
fmt.Println(myMap.GetP("foo"))
// Output: 3 true
fmt.Println(myMap.GetS(3))
// Output: foo true
Edit: Added example code
Upvotes: 0
Reputation: 892
Assuming you don't need any specific mapping and the player integer values have the sequence 0,1,2,3,...,25, you can generate the players symbols directly without using the maps as shown in following snippet :-
type player int
func ToSymbol(p player) string {
return fmt.Sprintf("%c", 'A' + p)
}
func ToPlayer(symbol string) player {
return player([]rune(symbol)[0] - 'A')
}
Upvotes: 0
Reputation: 11044
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.
Upvotes: 1
Reputation: 273834
[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)
}
Upvotes: 4