简体   繁体   中英

How to update map values in Go

I want to build a map with string key and struct value with which I'm able to update struct value in the map identified by map key.

I've tried this and this which doesn't give me desired output.

What I really want is this:

Received ID: D1 Value: V1
Received ID: D2 Value: V2
Received ID: D3 Value: V3
Received ID: D4 Value: V4
Received ID: D5 Value: V5

Data key: D1 Value: UpdatedData for D1
Data key: D2 Value: UpdatedData for D2
Data key: D3 Value: UpdatedData for D3
Data key: D4 Value: UpdatedData for D4
Data key: D5 Value: UpdatedData for D5

Data key: D1 Value: UpdatedData for D1
Data key: D2 Value: UpdatedData for D2
Data key: D3 Value: UpdatedData for D3
Data key: D4 Value: UpdatedData for D4
Data key: D5 Value: UpdatedData for D5

You can't change values associated with keys in a map, you can only reassign values.

This leaves you 2 possibilities:

  1. Store pointers in the map, so you can modify the pointed object (which is not inside the map data structure).

  2. Store struct values, but when you modify it, you need to reassign it to the key.

1. Using pointers

Storing pointers in the map: dataManaged := map[string]*Data{}

When you "fill" the map, you can't use the loop's variable, as it gets overwritten in each iteration. Instead make a copy of it, and store the address of that copy:

for _, v := range dataReceived {
    fmt.Println("Received ID:", v.ID, "Value:", v.Value)
    v2 := v
    dataManaged[v.ID] = &v2
}

Output is as expected. Try it on the Go Playground .

2. Reassigning the modified struct

Sticking to storing struct values in the map: dataManaged := map[string]Data{}

Iterating over the key-value pairs will give you copies of the values. So after you modified the value, reassign it back:

for m, n := range dataManaged {
    n.Value = "UpdatedData for " + n.ID
    dataManaged[m] = n
    fmt.Println("Data key:", m, "Value:", n.Value)
}

Try this one on the Go Playground .

I am learning Golang and Google brought me here. One way is to create a DataStore struct. I came up with this [see here][1]. Do let me know if this is a good way to do.


import (
    "fmt"
)

type Data struct {
    key   string
    value string
}

type DataStore struct {
    datastore map[string]Data
}

func newDataStore() DataStore {
    return DataStore{make(map[string]Data)}
}

/*
Puts the key and value in the DataStore.
If the key (k) already exists will replace with the provided value (v).
*/
func (ds *DataStore) put(k, v string) {
    dx := Data{key: k, value: v}
    ds.datastore[k] = dx
}

/*
Returns true, if the DataStore has the key (k)
*/
func (ds *DataStore) containsKey(k string) bool {
    if _, ok := ds.datastore[k]; ok {
        return ok
    }
    return false
}

/*
Puts the key and value in the DataStore, ONLY if the key (k) is not present.
Returns true, if the put operation is successful,
false if the key (k) ia already present in the DataStore
*/
func (ds *DataStore) putIfAbsent(k, v string) bool {
    if val, ok := ds.datastore[k]; ok {
        fmt.Println("datastore contains key: ", k, "with value =", val, " --- ", ok)
        return false
    }

    fmt.Println("datastore does not contain ", k)
    dx := Data{key: k, value: v}
    ds.datastore[k] = dx
    return true
}

/*
Returns the Data value associated with the key (k).
*/
func (ds *DataStore) get(k string) Data {
    return ds.datastore[k]
}

/*
Removes the entry for the given key(k)
*/
func (ds *DataStore) removeKey(k string) {
    delete(ds.datastore, k)
}

/*
Removes the entry for the given key(k)
*/
func (ds *DataStore) removeKeys(k ...string) {
    for _, d := range k {
        delete(ds.datastore, d)
    }
}

/*
Prints the keys and values
*/
func (ds *DataStore) print() {
    for k, v := range ds.datastore {
        fmt.Println(k, " ", v)
    }
}

func main() {
    fmt.Println("Hello, playground")
    ds := newDataStore()
    ds.print()
    ds.put("D1", "V1")
    ds.put("D2", "V2")
    ds.put("D3", "V3")  
    fmt.Println("datastore with initial values")

    ds.print()

    ds.put("D1", "UpdatedData for D1")
    ds.put("D2", "UpdatedData for D2")
    ds.put("D3", "UpdatedData for D3")
    fmt.Println("datastore with updated values")

    ds.print()
    
    fmt.Println("datastore: putIfAbsent");
    ds.putIfAbsent("D3", "Duplicate Key")
    ds.putIfAbsent("D4", "V4")
    ds.putIfAbsent("D5", "V5")
    
    fmt.Println("datastore with new values")

    result := ds.get("D1")
    fmt.Println("fetching the value for D1: result: ", result)

    testKey := "D4"
    //testKeys := [2]string{"D5", "D2"}
    
    fmt.Println("datastore: containsKey: ")

    if ok := ds.containsKey(testKey); ok {
        fmt.Println("has key ", testKey, ok)
    } else {
        fmt.Println("has no key ", testKey, ok)
    }

    ds.print()
    ds.removeKey(testKey)

    fmt.Println("afer removing ", testKey)
    ds.print()

    fmt.Println("afer removing ", "D5", "D1")
    ds.removeKeys("D5", "D1")
    ds.print()
}```



  [1]: https://play.golang.org/p/4FEGkImcCKB

The question is about struct, but I found it while searching for "how to update a key if it exists, or insert it if it doesn't exist".

I have a map T -> number and I want to count how many times a key occurs in an array, or slice:

    data := []int{0,0,0,1,1,2,3,3,3,3,4}
    m := make(map[int]int, 0)
    for _, val := range data {
        m[val] = m[val] + 1
    }

How it works: if the key is absent, m[val] produces the 'zero' form of the type of the map value. With numerical values, this is 0 . Then I add 1 , and store again in the slot m[val] . This is perfect as the first value.

What happens when key does not exist:

1. m[val] = m[val] + 1
2. m[val] = 0 + 1
3. m[val] = 1

What happens when key exists:

1. m[val] = m[val] + 1
2. m[val] = 1 + 1
3. m[val] = 2

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM