1

I want to create map which stores routes from one point to another, distance between them will be used as values in the map.

type Route struct {
    start  string
    finish string
}

m := make(map[Route]int)
v := Route{start: "A",
            finish: "B"}
m[v] = 42

Distance from A to B equals to distance from B to A.

w := Route{start: "B",
        finish: "A"}

How can I get m[w] without pushing m[w] = 42 into the map again because v and w are the same route.

P.S In other words, is it possible to override rules when one Route equals to another Route when using Route as a key in map?

4
  • 1
    You cannot. Or use comma-okay to see if B-->A is in the map and query A-->B if not. Commented Jan 9, 2018 at 13:01
  • They may be the same route or distance but they are not the same Route. You need to come up with a type that is the same for both. Commented Jan 9, 2018 at 13:03
  • Is it possible to override the rules when one Route equals to another Route? Commented Jan 9, 2018 at 13:06
  • No. Equality is a fixed language construct and not user definable. Commented Jan 9, 2018 at 13:45

3 Answers 3

2

Define map[Route]int as a user-defined type like RouteDistance.

type RouteDistance map[Route]int

And then define a Find function on that type, to check for bi-directional routes and return the distance.

func (rd RouteDistance) Find(r Route) (d int, ok bool) {
    routeDistance := map[Route]int(rd)
    d, ok = routeDistance[r]
    if ok {
        return
    }
    d, ok = routeDistance[Route{start: r.finish, finish: r.start}]
    if ok {
        return
    }
    return -1, false
}

Initiate the RouteDistance with just one-directional route and distance.

rd := make(RouteDistance)
rd[Route{start: "A", finish: "B"}] = 42

Get bi-directional distance for routes.

rd.Find(Route{start: "A", finish: "B"})
rd.Find(Route{start: "B", finish: "A"})

The working code is in Playground

Sign up to request clarification or add additional context in comments.

1 Comment

This line routeDistance := map[Route]int(rd) is unneeded, you can index rd just like a normal map.
1

Index the map with a Route where finish and start are swapped:

m[Route{start: w.finish, finish: w.start}]

If you want to check both directions, create a helper function for it:

var m = make(map[Route]int)

func dist(r Route) int {
    if d, ok := m[r]; ok {
        return d
    }
    return m[Route{start: r.finish, finish: r.start}]
}

Note that dist() will return 0 if neither direction is in the map. If you want to return this info too:

func dist(r Route) (d int, found bool) {
    d, found = m[r]
    if !found {
        d, found = m[Route{start: r.finish, finish: r.start}]
    }
    return
}

Try it on the Go Playground.

Comments

1

A few ways to do this without pushing an additional value. Either perform two map accesses:

r := Route{
    start: "B",
    finish: "A",
}
d, ok := m[r]
if !ok {
    r.start = "B"
    r.finish = "A"
    d, ok = m[r]
}
if !ok {
    // value not found
}

Or for every map store and access, sort the start and finish:

func Put(start, finish string, d int) {
    r := Route{start, finish}
    if start > finish {
        r.start = finish
        r.finish = start
    }
    m[r] = d
}

func Get(r Route) int {
    if r.start > r.finish {
        r.start, r.finish = r.finish, r.start
    }
    m[r] = d
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.