0

I am very new to Go language. I am struggling with following usecase.

I want to store session id (string) and reqeust No (string) in a map for duplicate checking. When there is no entry in the map, it should create one, else it should return a flag saying the entry already exists.

package main

import "fmt"

func main() {
    mySessionData := make(map[string]map[string]bool)

    var ret bool
    ret = chkDuplicate(mySessionData, "session1", "1")
    fmt.Println(mySessionData)
    ret = chkDuplicate(mySessionData, "session1", "2")
    fmt.Println(mySessionData)
    ret = chkDuplicate(mySessionData, "session1", "3")
    fmt.Println(mySessionData)
    ret = chkDuplicate(mySessionData, "session1", "2")
    fmt.Println(mySessionData)
    ret = chkDuplicate(mySessionData, "session1", "4")
    fmt.Println(mySessionData)
    fmt.Println(ret)

    delete(mySessionData, "session1")
    fmt.Println(mySessionData)

}

func chkDuplicate(m map[string]map[string]bool, sess string, Reqno string) bool {
    var found bool
    val, found := m[sess][Reqno]
    if !found {
        fmt.Println(val)
        valu := make(map[string]bool)
        valu[Reqno] = true
        m[sess] = valu
        return !found

    }
    return !found
}

The problem I am facing is that the value is over written every time the function is called. What am I doing wrong here?

3
  • you're creating a new map each time found is false, don't do that, check if m[sess] is nil and only then create it, if it's not nil just set m[sess][Reqno] to true. play.golang.org/p/VlPY8UmRU-5 Commented May 9, 2018 at 9:40
  • You're not using val variable anywhere Commented May 9, 2018 at 9:40
  • This code will not work as expected since you are creating a new map for req every time you check for duplicates. Commented May 9, 2018 at 9:43

3 Answers 3

1

It's often simpler to use a struct key instead of a multi-level map: https://play.golang.org/p/WFlGi1rrVOm

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

Comments

1

You only have to create a value of the inner map (the session map) if a map for the given session ID does not yet exists (and not if the given request number is not in it), else you clear any previously stored request numbers from it.

Since you are using bool as the value type for the inner map (session map), you can exploit this to write simpler code (indexing a map with a key that is not in it will yield the zero value of the value type, which is false for the bool type, properly telling the key is not in it):

func chkDuplicate(m map[string]map[string]bool, sess string, Reqno string) bool {
    sessMap := m[sess]
    if sessMap == nil {
        m[sess] = map[string]bool{Reqno: true}
        return false
    }

    if sessMap[Reqno] {
        return true
    }
    sessMap[Reqno] = true
    return false
}

Testing it:

func main() {
    mySessionData := make(map[string]map[string]bool)

    for _, reqNo := range []string{"1", "2", "3", "2", "4"} {
        ret := chkDuplicate(mySessionData, "session1", reqNo)
        fmt.Println(ret, mySessionData)
    }

    delete(mySessionData, "session1")
    fmt.Println(mySessionData)
}

Output (try it on the Go Playground):

false map[session1:map[1:true]]
false map[session1:map[1:true 2:true]]
false map[session1:map[1:true 2:true 3:true]]
true map[session1:map[2:true 3:true 1:true]]
false map[session1:map[2:true 3:true 4:true 1:true]]
map[]

Note that bool –although may be small–does require memory. Since we can query if a key is in the map, we may opt to use a value type that requires no memory, such as an empty struct (struct{}). With that, it may look like this:

func chkDuplicate(m map[string]map[string]struct{}, sess string, Reqno string) bool {
    sessMap := m[sess]
    if sessMap == nil {
        m[sess] = map[string]struct{}{Reqno: struct{}{}}
        return false
    }

    if _, ok := sessMap[Reqno]; ok {
        return true
    }
    sessMap[Reqno] = struct{}{}
    return false
}

Testing and result is (almost) the same, try it on the Go Playground.

A word of warning: judging from the example, it looks you want to use this to track if a (web) request has been served previously, where usually multiple goroutines are involved. This solution is not safe for concurrent use.

Comments

0

sess variable always equals session1, so you just override value for key session1. You have to have indistinguishable keys.

If you want just check duplicates, just to this:

package main 

import "fmt"

func main() {
    mySessionData := make(map[string]bool)

    chkDuplicate(mySessionData, "session1", "1")
    chkDuplicate(mySessionData, "session1", "1")
    chkDuplicate(mySessionData, "session2", "1")
    fmt.Println(mySessionData) # two keys printed
}

func chkDuplicate(m map[string]bool, sess string, Reqno string) bool {
    key := fmt.Sprintf("%s-%s", sess, Reqno)
    _, found := m[key]
    if !found {
       m[key] = true    
    }
   return !found
}

1 Comment

I am looking for something that is similar to Perl Hash of Hash. So variable mySessionData should be able to return value true when I access mySessionData["session1"]["2"] but return nil when say mySessionData["session1"]["6"]

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.