Want to take a map to a slice structure - go

I have a map with a key and a value structure that i want to put into a simple slice.
The struct I want to store the values as ,
type Attribute struct {
AttId container.AttrID
AttMess []json.RawMessage
}
The current loop I have is something like this which takes the keys from the existing map,
keys := make([]container.AttrID, 0, len(AttId))
for k := range AttId {
keys = append(keys, k)
}
for _, k := range keys {
fmt.Println(k, AttId[k])
}
How would I construct a slice that holds the keys and values inside attributes with the struct above? I'm a bit lost if you can actually make this.
Thanks!

You should simply range over the map and construct instances of the struct. Assuming the map values are []json.RawMessage types:
attrs:=make([]Attribute,0,len(attributes))
for k,v:=range attributes {
attrs=append(attrs,Attribute{AttributesId:k, AttributesMessage:v})
}

Related

Alternative to using map as key of map in GO

I want to tag my maps with a timestamp, there will be various maps - dynamically generated. The keys will be repeated, so if the same map appears I want to updated its values
I'm getting the maps from external sources and want to registered when they are read
Ever so often I want to iterate the map and find those maps that didn't update for a while
a = map[string]string{"a":1, "b":2}
b = map[map[string]string]time.Time{}
b[a] = 1
I understand it's not supported but I was wondering what are the some ways of doing it?
The first thing that comes to mind is: serialize the map into string and use it as key,,?
Make a struct that will keep the info you need:
type MyMap struct {
timestamp time.Time
m map[string]string
}
And lookup by iterating over a slice of such structs:
func lookup(needle map[string]string, haystack []MyMap) (MyMap, bool) {
for _, myMap := range haystack {
if reflect.DeepEqual(needle, myMap.m) {
return myMap, true
}
}
return nil, false
}
Alternatively, convert your map to JSON and use the result as the key:
b, _ := json.Marshal(myMap)
key := string(b)
m, ok := myMaps[key] // myMaps is map[string]MyMap
if !ok {
myMaps[key] = myMap
}
Apparently, json.Marshal sorts the map's keys before marshaling, so this should be a reliable solution.

Optimal way to add or remove slice element in Go without broke elements order

Assume I have []struct{} and I need to know whether an element with id = A exists in the slice. If exists, the element will be removed or moved to index 0 according to request in user input. So, how to find an element in golang slice in optimal way without check each element? Or, is using slice.contains(obj) enough? Then, if the element exists, I will do action according to request in user input. If the request is remove, I will remove it without broke the elements order. But if the request is add, I will move the element to index 0.
Note: The function will be often called.
Thank you.
It is not difficult to write function to find element by iterating over slice:
func contains(s []your_struct, e int) (bool, int) {
for idx, a := range s {
if a.id == e {
return true, idx
}
}
return false, -1
}
If you a going to call the function often it may be useful to sort the slice by id field and implement binary search over slice of your_struct.
If the slice is not very big you can create additional data structure - map[int]int and keep the indexes of elements of the slice in this map. But in this case you need to synchronize content of your slice and the map when you are modifying one of them:
your_map := make(map[int]int)
if idx, ok := your_map[id]; ok {
// ...
}
If you need to check many times then
it's better to create a map[string]int of id field one time.
And every time just check map contains that id or not
Here,id as key and slice index as value
mp := make(map[string]int)
for idx, a := range yourStuctSlice {
mp[a.id] = idx
}
if idx, ok := mp[id]; ok {
// remove the element using idx
}
If new element added in slice then update the map also
mp[newElement.id] = true
If you want to remove searched element you can remove by slice index
func RemoveIndex(s []yourStuct, index int) []int {
return append(s[:index], s[index+1:]...)
}
if idx, ok := mp[id]; ok {
yourStuctSlice = RemoveIndex(yourStuctSlice , idx)
delete(mp , id); // Remove from map also for next search
}

go map search using values in a map

I have a map structured like map[string][]string. Now I have to find all keys which have the required values in the value slice. I can do something like this:
// allsvc is map[string][]string
var newsl []string
for k, v := range allsvc {
for _, val := range v {
if v == "type1" || v == "type2" {
newsl.append(k)
}
}
}
The map allsvc has atleast a half million entries at any given time, and the lookup is quite frequent. I get the allsvc map as an ouput of a 3rd party library and then I have to search in it using values in my api and provide a response. Given the high frequency of lookup not using keys but with values, the way i have done it makes my api response time to be in the seconds. Is there a way to better performance (speed of lookup)?
If you will query that map multiple times, it might be worth spending some time re-arranging it when you get it so that you can then query it faster.
It seems you need to invert the relationships, making the values in allsvc the keys in the new map, and having the keys as values so that you can then just make lookups in the new map.
This can be a way to re-arrange the map:
func arrangeMap(oldMap map[string][]string) map[string][]string {
newMap := make(map[string][]string)
for k, v := range oldMap {
for _, val := range v {
newMap[val] = append(newMap[val], k)
}
}
return newMap
}
See here a playground showing the idea:
https://play.golang.org/p/0ThZlX9xUn

r.ParseForm field order

So I would like to preserve the order of the post fields.
But now using the http ParseForm function it will put the fields into a map which will have a different order each time.
The original query : a=1&b=2&c=3 can become b=2&c=3&a=1 or any random order.
Since I hash the query and compare it with the hash of the user his query the hash on my side changes all the time since the order of the fields are random.
Code:
func parsePostQuery(r *http.Request, hashQuery string) bool {
urlquery := url.Values{}
r.ParseForm()
for k, p := range r.Form {
urlquery.Set(k, p[0])
}
//some psuedo code
if hashQuery == hash(urlquery.Encode()){
return true
}
return false
}
How can I parse the fields that are submitted by the user and keep the field order of the user?
Sidenote: I do not know the field names in advance.
In the same area as other answers, you will need the clients to calculate their hash by alphabetizing all parameters before hashing. The code you've supplied should work fine; values.Encode() will sort the values by key on it's own:
Encode encodes the values into “URL encoded” form ("bar=baz&foo=quux") sorted by key.
There's no way to preserve the ordering of the client; in fact, what you receive may not even be how it was ordered on the client end. However unlikely, there's no guarantee that intermediate processes won't change things.
tl;dr: You can't implicitly. The underlying data structure is a map, for which the order is not guaranteed. You need to take additional steps.
However Go maps in action shows an easy way to access the map in a sorted way. You create a slice of the keys, sort that slice and access the map value by iterating over the keys in the sorted slice.
For your example, it would look something like this
package main
import (
"crypto/md5"
"fmt"
"io"
"sort"
)
func main() {
// Which is the same structure as url.Values()
var m map[string][]string = make(map[string][]string)
m["c"] = []string{"19.95"}
m["b"] = []string{"foo", "bar", "baz"}
m["a"] = []string{"1"}
// Note that playground is deterministic, so the order should be preserved there
// However, you can not rely on that in the real world
fmt.Println("Unsorted")
for k, v := range m {
fmt.Println("Key:", k, "Value:", v)
}
var keys []string
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
hash := md5.New()
fmt.Println("\nSorted")
for _, k := range keys {
fmt.Println("Key:", k, "Value:", m[k])
// Add Key/Value pair to hash
fmt.Printf("\tAdding KEY '%s' to hash\n", k)
io.WriteString(hash, k)
for _, v := range m[k] {
fmt.Printf("\tAdding VALUE '%s' to hash\n", v)
io.WriteString(hash, v)
}
}
fmt.Printf("\nHash: %x", hash.Sum(nil))
}
Run above code on Playground
You can read the request body and check for the form parameters. They will appear in the same order as in the request(hope your client application is also aware of this order preserving)
You can create a reader for reading the request body. A sample code looks like
body, err := ioutil.ReadAll(r.Body)
if err != nil {
fmt.Println("Reading Error ")
return
}
fmt.Println("Req Body : ", string(body))
Note : Be aware of the content type

Get index of element from array / slice or key of value from map in Go?

I have an enumerated list of strings (which are constant, e.g. a list of countries), that I'd like to be able to get the string when providing the enumerated int value, and vice-versa be able to get the enumerated int value when providing the string. This is in order to translate between the two for database transactions.
var MyData = [...]string {
"string1", // index 0
"string2", // index 1
"string3", // index 2
}
That's easy for a language like python, where one can just do something like MyData[1] to get "string2" and MyData.index("string2") to get 1.
A few possible solutions would be to
write my own function to get the index by iterating over the array / slice
sort the array / slice and use a search function to return index (though this doesn't allow for an unsorted sequence, which is what I'd prefer)
maintain a map and an array that mirror each other, which is prone to errors.
Speaking of maps, can one access the key of a particular value? Then I could simply have a map like the following, and be able to get the string key when providing the int value.
var MyData = map[string]int {
"string1": 0,
"string2": 1,
"string3": 2,
}
UPDATE: Before I accept my answer, I want to explain the problem more thoroughly, which I know must be fairly common. I basically have a set of strings that are constant (such as a list of countries) each with an associated integer value. In my database I simply store the integer to conserve space, since there are millions of entries. But when I display an entry from the database I need to display the string value for it to be readable to a user. A simple array will do for that. However, I also need to add entries to the database (such as a new person and their country of residence) and in this scenario need to translate from the country string which is entered in a form to that integer value. Again, this is just an example use case, but the goal remains the same. I need a table that can translate in both directions between a string value and an enumerated int value. The most obvious thing to do is to maintain an array (for the int to string translation) and a map (for the string to int translation). I'd prefer not to manually maintain both variables, since this is prone to errors. So my solution below is to maintain just a single array, and have the constructor method automatically build the map at runtime when the program is first run. This has the advantage of not needing to iterate over the entire array when I fetch the integer value based on the string (which was the other proposed solution).
In both cases you should just use the built in range function.
for k, v := range MyData {
}
for i, v := range ThisArray {
}
for i, _ := range ThisArrayIndexOnly {
value := ThisArrayIndexOnly[i]
}
You can build helper functions or whatever you like on top of this but range is fundamentally the mechanism available for accessing that data. If you want an "indexof" function it would be
for i, v := range ArrayPassedIntoFunction {
if v == ValuePassedIntoFunction {
return i
}
}
return -1
To get the value, you of course would just do MyArray[i] including a bounds check or whatever. Note the pseudo code above is written in a style that indicates it's an array but virtually the same code will work for a map, I would just typically use the var name k instead of i.
Assume you want getting index of word in the data of array
data := [...] {"one","two","three"}
or fixed length array
data := [3] {"one","two","three"}
create function
func indexOf(word string, data []string) (int) {
for k, v := range data {
if word == v {
return k
}
}
return -1
}
to get value from function above, to match the type, pass the array with array[:] like below
fmt.Println(indexOf("two", data[:]))
Here's a solution that I mentioned earlier, which works well for static slices (which is my use case). Iterating over the slice every time I want the index of a value adds unnecessary delay, especially since my data is static during runtime. This just creates a struct which initializes the slice and creates the corresponding inverse map. And then I would use the GetKey and GetVal methods to get either the string 'key' by providing the int 'value', or get the int 'value' by providing the string 'key'. Perhaps there's already a way to get the key of a particular value of a map in Go.
type MyData struct {
dataslice []string
datamap map[string]int
}
func NewMyData() *MyData {
m := new(MyData)
m.dataslice= []string {
"string1",
"string2",
"string3",
}
m.datamap = make(map[string]int)
for x := range m.dataslice {
m.datamap[m.dataslice[x]] = x
}
return m
}
func (m *MyData) GetKey(x int) string {
return m.dataslice[x]
}
func (m *MyData) GetVal(x string) int {
return m.datamap[x]
}

Resources