Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go: append directly to slice found in a map

Tags:

go

I wanted to create a map of slices where values are appended to the corresponding slice. However, when trying to append directly to the slice returned by accessing it (see comment below), it would not be stored, so I had to go with the long form access (line below the comment).

Why is it so? I expected the access to the map to return some sort of pointer, so in my mind mappedAminoAcid == aminoAcidsToCodons[aminoAcid]; clearly, I'm wrong.

Thanks!

aminoAcidsToCodons := map[rune][]string{}
for codon, aminoAcid := range utils.CodonsToAminoAcid {
    mappedAminoAcid, ok := aminoAcidsToCodons[aminoAcid]

    if ok {
        // NOT WORKING: mappedAminoAcid = append(mappedAminoAcid, codon)
        aminoAcidsToCodons[aminoAcid] = append(mappedAminoAcid, codon)
    } else {
        aminoAcidsToCodons[aminoAcid] = []string{codon}
    }
}
like image 516
jonathanGB Avatar asked Sep 29 '17 15:09

jonathanGB


1 Answers

append returns a new slice if the underlying array has to grow to accomodate the new element. So yes, you have to put the new slice back into the map. This is no different from how strings work, for instance:

var x map[string]string
x["a"] = "foo"

y := x["a"]
y = "bar"

// x["a"] is still "foo"

To get the behaviour you expected, you'd have to use slice pointers.

aminoAcidsToCodons := map[rune]*[]string{}
for codon, aminoAcid := range utils.CodonsToAminoAcid {
    mappedAminoAcid := aminoAcidsToCodons[aminoAcid]
    *mappedAminoAcid = append(*mappedAminoAcid, codon)
}

That being said, since nil is a perfectly fine first argument for append, you can simplify your code to

aminoAcidsToCodons := map[rune][]string{}
for codon, aminoAcid := range utils.CodonsToAminoAcid {
    aminoAcidsToCodons[aminoAcid] = append(aminoAcidsToCodons[aminoAcid], codon)
}
like image 185
Peter Avatar answered Oct 06 '22 00:10

Peter