4

I can't find a good way to do this. I want to have a map from a list of sorted key-value pairs.

type Tag struct {
  key   string
  value string
}

type SortedTag []Tag // sorted list of tags.
map[SortedTags]T // cannot do.

I can solve this problem by joining all the key-value pairs with a delimiter, but I feel like this is inefficient and error prone in many ways. Converting back to the key-value pair is cumbersome because we need to split the input. moreover, if the key value pair can be anything, that means we have to escape it.

If it was python, I would've stored Tag as N-tuple of sorted 2-tupless.

If it was java, I would've created a composite object with Map<String,String> with equals() checking against the other hash map, hashCode() returning the xor of all the hashes of the map (xor since it is commutative thus we can iterate the map in any order to compute this value).

In go, I can't think of any other good way.

5
  • I do not understand your question... First, I think that it does not matter if your list is sorted or not if you want to make a map from the list. Then, I do not understand the type of your map. Why is it not map[string]string? And finally, why not go over all the elements in the list and save them to the map? Commented Oct 25, 2014 at 5:30
  • Answers. * I have a sorted map because I want to have check that the list of key-value pairs are equal, and best way to ensure that when there's no set type primitive is keeping them sorted by key. * i do NOT want it to be `map[string]string because of the reason I've listed below. * I don't understand your third question. Commented Oct 25, 2014 at 5:37
  • As I understand you do not want to search your list by key, you only want to check if it already has a specific key/value pair. Right? In my third question I assumed that the problem is to construct a map from the list. Commented Oct 25, 2014 at 5:40
  • 3
    The hash and equality functions used by maps are part of the runtime. The application cannot control or replace these functions. Creating a string from the sorted items is probably the best option. Commented Oct 25, 2014 at 5:44
  • Maps support structs of comparable types as keys as far as I know. So if I finally understand the question, the resulting map will be of type map[Tag]int. Or something like that. Basically the value type of this map does not matter because it looks like you want sets, not maps. Commented Oct 25, 2014 at 5:47

2 Answers 2

3

For example,

package main

import "fmt"

type Tag struct {
    Key   string
    Value string
}

type Tags []Tag

type TagsValue struct {
    // some type used as Tags value
}

type TagsMapValue struct {
    Tags
    TagsValue
}

type TagsMapKey string

type TagsMap map[TagsMapKey]TagsMapValue

func NewTagsMapKey(tags Tags) TagsMapKey {
    b := []byte{}
    for _, tag := range tags {
        b = append(b, tag.Key...)
        b = append(b, tag.Value...)
    }
    return TagsMapKey(b[:len(b)])
}

func (m *TagsMap) AddElement(tags Tags, tagsValue TagsValue) {
    mapKey := NewTagsMapKey(tags)
    mapValue := TagsMapValue{Tags: make(Tags, 0, len(tags)), TagsValue: tagsValue}
    i := 0
    for _, tag := range tags {
        key := string(mapKey[i : i+len(tag.Key)])
        i += len(tag.Key)
        value := string(mapKey[i : i+len(tag.Value)])
        i += len(tag.Value)
        mapValue.Tags = append(mapValue.Tags, Tag{Key: key, Value: value})
    }
    (*m)[mapKey] = mapValue
    return
}

func main() {
    m := make(TagsMap)
    sortedTags := Tags{
        {Key: "key1", Value: "value1"},
        {Key: "key7", Value: "value7"},
        {Key: "key7", Value: "value49"},
        {Key: "key42", Value: "value42"},
    }
    m.AddElement(sortedTags, TagsValue{})
    for k, v := range m {
        fmt.Println("Tags Key:", k)
        fmt.Println("   Tags:      ", v.Tags)
        fmt.Println("   Tags Value:", v.TagsValue)
    }
}

Output:

Tags Key: key1value1key7value7key7value49key42value42
   Tags:       [{key1 value1} {key7 value7} {key7 value49} {key42 value42}]
   Tags Value: {}

If you are simply trying to test for Tags set membership,

package main

import "fmt"

type Tag struct {
    Key   string
    Value string
}

type Tags []Tag

type TagsSetKey string

type TagsSet map[TagsSetKey]Tags

func NewTagsSetKey(tags Tags) TagsSetKey {
    b := []byte{}
    for _, tag := range tags {
        b = append(b, tag.Key...)
        b = append(b, tag.Value...)
    }
    return TagsSetKey(b[:len(b)])
}

func (m *TagsSet) AddElement(tags Tags) {
    setKey := NewTagsSetKey(tags)
    setValue := make(Tags, 0, len(tags))
    i := 0
    for _, tag := range tags {
        key := string(setKey[i : i+len(tag.Key)])
        i += len(tag.Key)
        value := string(setKey[i : i+len(tag.Value)])
        i += len(tag.Value)
        setValue = append(setValue, Tag{Key: key, Value: value})
    }
    (*m)[setKey] = setValue
    return
}

func (m *TagsSet) IsMember(tags Tags) bool {
    return (*m)[NewTagsSetKey(tags)] != nil
}

func main() {
    m := make(TagsSet)
    sortedTags := Tags{
        {Key: "key1", Value: "value1"},
        {Key: "key7", Value: "value7"},
        {Key: "key7", Value: "value49"},
        {Key: "key42", Value: "value42"},
    }
    m.AddElement(sortedTags)
    for k, v := range m {
        fmt.Println("Tags Key:", k)
        fmt.Println("   Tags: ", v)
    }
    // In set
    fmt.Println(m.IsMember(sortedTags))
    // Not in set
    sortedTags[0].Key = "key0"
    fmt.Println(m.IsMember(sortedTags))
}

Output:

Tags Key: key1value1key7value7key7value49key42value42
   Tags:  [{key1 value1} {key7 value7} {key7 value49} {key42 value42}]
true
false
Sign up to request clarification or add additional context in comments.

Comments

0

if you are after (sorted) tuples, you can check out kmanley/golang-tuple

It does have examples of sorting tuples.

This is different from deckarep/golang-set, which can also be helpful for managing those Tag.

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.