I would like to loop on the name of my tables to add the associations defined by the symbol "_".
If table a_b and a then b exists then a = [b], b = [a].
Finally, I do not have to print the tables containing a "_" in the name
Struct
// Table with Fields and Assoc
type Table struct {
Name string
Assoc []Assoc
}
// Assoc is a name of associated Table
type Assoc struct {
Name string
}
tables := []string{
"a",
"b",
"c",
"d",
"f",
"a_b",
"a_c",
"a_d_f",
"c_d",
}
var tbls []Table
for _, t := range tables {
if strings.Contains(t, "_") {
// Split to find "_" like assoc := strings.Split(t, "_") ?
// append in struct "Table{Name:a, Assoc: [b,c,d,f]}"
// append in struct "Table{Name:b, Assoc: [a]}"
// append in struct "Table{Name:c, Assoc: [a,d]}"
// append in struct "Table{Name:d, Assoc: [a,c,f]}"
// append in struct "Table{Name:f, Assoc: [a,d]}"
} else {
n := Table{
Name: t,
}
tbls = append(tbls, n)
}
}
Return like fmt.Println(tbls) :
[{a [b,c,d,f]} {b [a]} {c [a,d]} {d [a,c,f]} {f [a,d]}]
Go Playground
Done the above mentioned using map
https://play.golang.org/p/8C5M0L-es6o
package main
import (
"fmt"
"strings"
)
// Table with Fields and Assoc
type Table struct {
Name string
Assoc map[string]int
}
// Assoc is a name of associated Table
// type Assoc struct {
// Name string
// }
func main() {
tables := []string{
"a",
"b",
"c",
"d",
"f",
"a_b",
"a_c",
"a_d_f",
"c_d",
}
var tbls = make(map[string]map[string]int)
for _, t := range tables {
if strings.Contains(t, "_") {
splitAssocs := strings.Split(t, "_")
for i:=0;i<=len(splitAssocs)-2;i++ {
for j:=(i+1);j<=len(splitAssocs)-1;j++{
_, ok := tbls[splitAssocs[i]]
if !ok{
tbls[splitAssocs[i]] = make(map[string]int)
}
_, ok = tbls[splitAssocs[j]]
if !ok{
tbls[splitAssocs[j]] = make(map[string]int)
}
tbls[splitAssocs[i]][splitAssocs[j]] = 1
tbls[splitAssocs[j]][splitAssocs[i]] = 1
}
}
} else {
_, ok := tbls[t]
if !ok{
tbls[t] = make(map[string]int)
}
}
}
fmt.Println(tbls)
}
Related
I have 2 lists, one list element type is structA, the other list element type is structB, there's common field string name between structA and structB. how to get intersection element which has same name between 2 lists and avoid o(n^2) time complexity using golang.
type structA struct {
name string
....
}
type structB struct {
name string
..
}
noted: name field in each list is not unique, so convert map way is not a solution
Having lists that are not unique does not prevent you from using a map; you can do something like the following (playground):
package main
import (
"fmt"
)
func main() {
type structA struct {
name string
otherfield int
}
type structB struct {
name string
differentField bool
}
aSlice := []structA{
{name: "foo", otherfield: 1},
{name: "foo", otherfield: 2},
{name: "unique", otherfield: 3},
{name: "one", otherfield: 4},
}
bSlice := []structB{
{name: "foo", differentField: true},
{name: "foo", differentField: false},
{name: "noIntersection", differentField: true},
{name: "one", differentField: false},
}
inA := make(map[string][]interface{})
for _, a := range aSlice {
inA[a.name] = append(inA[a.name], a)
}
intersect := make(map[string][]interface{})
for _, b := range bSlice {
if _, ok := intersect[b.name]; ok {
intersect[b.name] = append(intersect[b.name], b)
continue
}
if a, ok := inA[b.name]; ok {
intersect[b.name] = append(a, b)
continue
}
}
fmt.Println(intersect)
}
I think you can try to use Maps in Golang. The average complexity time is O(n) because a Map in golang base on a Hash table.
Example Code:
aMap := make(map[string][]*structA)
for _,a := range aList {
aMap[a.name] = append(aMap[a.name], a)
}
bMap := make(map[string][]*structB)
for _,b := range bList {
bMap[b.name] = append(bMap[b.name], b)
}
//get an intersection of aList and bList
itersections := make([]*structB, 0, len(aList))
for k,v := range aMap {
if b, ok := bMap[k];ok {
itersections = append(intersections, b...)
}
}
I have a custom type looped to display all of the fields given. The purpose of this is to be able to format it a little better than a long, endless single line. However, printing it within the loop won't work, everything I've tried simply prints a string of a single line versus all 4 from the array.
type Rule struct {
Value string `json:"value"`
Tag string `json:"tag"`
Id string `json:"id"`
}
func test() string {
get, err := getRules()
if err != nil {
panic(err)
}
for _, r := range get {
fmt.Printf("value:%v, tag:%v, id:%v\n", r.Value, r.Tag, r.Id)
}
// need to return it as a string like below
return fmt.Sprintf("%v", list)
}
is there a way to easily create a variable list out of that? So I can display it as a string? That prints:
value:x0, tag:t0, id:i0
value:x1, tag:t1, id:i1
value:x2, tag:t2, id:i2
value:x3, tag:t3, id:i3
from fmt.Printf(get)
[{x0 t0 i0} {x1 t1 i1} {x2 t2 i2} {x3 t3 i3}]
I'm essentially trying to convert a custom type to a string so that I can display it better.
You should implement String method.
package main
import (
"fmt"
"strings"
)
type Rule struct {
Value string `json:"value"`
Tag string `json:"tag"`
Id string `json:"id"`
}
func (g *Rule) String() string {
return fmt.Sprintf("value:%s, tag:%s id:%s\n", g.Value, g.Tag, g.Id)
}
type RuleList []Rule
func (g RuleList) String() string {
slist := make([]string, 0)
for _, v := range g {
slist = append(slist, v.String())
}
return strings.Join(slist, "")
}
func main() {
g1 := Rule{Value: "hello", Tag: "1", Id: "1"}
g2 := Rule{Value: "hello", Tag: "1", Id: "1"}
g3 := Rule{Value: "hello", Tag: "1", Id: "1"}
glist := RuleList{g1, g2, g3}
fmt.Println(glist)
}
You can achieve this by implementing Stringers interface [more about Stringers]
package main
import "fmt"
type Dummy struct{
Value, Tag, Id string
}
func (r Dummy) String() string {
return fmt.Sprintf("value:%v, tag:%v, id:%v\n", r.Value, r.Tag, r.Id)
}
func main(){
ls := make([]Dummy,0)
ls = append(ls, Dummy{"x0", "t0", "i0"})
ls = append(ls, Dummy{"x1", "t1", "i1"})
ls = append(ls, Dummy{"x2", "t2", "i2"})
ls = append(ls, Dummy{"x3", "t3", "i3"})
fmt.Println(Dummy{"x0", "t0", "i0"})
fmt.Println(ls)
}
I want to create a function called merge() that takes in two values of the same struct, but of any struct, and returns the merged values of the two structs.
I want the first value to take precedence. For example, if there are two structs a and b, after calling merge(a,b), if there are fields that both a and b contain, I want it to have a's value for that given field.
What would be the best way to implement this?
https://play.golang.org/p/7s9PWx26gfz
type cat struct {
name string
color string
age int
}
type book struct {
title string
author string
}
func main() {
c1 := cat{
name: "Oscar",
color: "",
age: 3,
}
c2 := cat{
name: "",
color: "orange",
age: 2,
}
c3 := merge(c1, c2)
// want: c3 = cat{
// name: "Oscar",
// color: "orange",
// age: 3,
// }
// another case...
b1 := book{
title: "Lord of the Rings",
author: "John Smith",
}
b2 := book{
title: "Harry Potter",
author: "",
}
b3 := merge(b1, b2)
// want: b3 = book{
// title: "Lord of the Rings",
// author: "John Smith",
// }
}
This is what I have so far:
// merges two structs, where a's values take precendence over b's values (a's values will be kept over b's if each field has a value)
func merge(a, b interface{}) (*interface{}, error) {
var result interface{}
aFields := reflect.Fields(a)
bFields := reflect.Fields(b)
if !reflect.DeepEqual(aFields, bFields) {
return &result, errors.New("cannot merge structs of different struct types")
}
aValOf := reflect.ValueOf(a)
bValOf := reflect.ValueOf(b)
resultValOf := reflect.ValueOf(result)
aValues := make([]interface{}, aValOf.NumField())
resultValues := make([]interface{}, resultValOf.NumField())
for i := 0; i < aValOf.NumField(); i++ {
if reflect.ValueOf(aValues[i]).IsNil() {
resultValues[i] = bValOf.Field(i).Interface()
break
}
resultValues[i] = aValOf.Field(i).Interface()
}
return &result, nil
}
Check this package https://github.com/imdario/mergo
Sample code:
package main
import (
"fmt"
"github.com/imdario/mergo"
)
type Foo struct {
A string
B int64
}
func main() {
src := Foo{
A: "one",
B: 2,
}
dest := Foo{
A: "two",
}
mergo.Merge(&dest, src)
fmt.Println(dest)
// Will print
// {two 2}
}
See it at playground: https://play.golang.org/p/9KWTK5mSZ6Q
Use custom types for fields in your target structs.
type firstString string
type firstInt int
type cat struct {
Name firstString
Color firstString
Age firstInt
}
type book struct {
Title firstString
Author firstString
}
Implement UnMarshalJSON for each custom type such that they only unmarshal for target values that are empty.
func (fs *firstString) UnmarshalJSON(bytes []byte) error {
if len(*fs) > 0 {
return nil
}
var s string
err := json.Unmarshal(bytes, &s)
if err != nil {
return err
}
*fs = firstString(s)
return nil
}
func (fi *firstInt) UnmarshalJSON(bytes []byte) error {
if *fi != 0 {
return nil
}
var i int
err := json.Unmarshal(bytes, &i)
if err != nil {
return err
}
*fi = firstInt(i)
return nil
}
If your data is coming via JSON, you can avoid the use of the merge function; just keep unMarshalling incoming JSON to the same struct. If your data is already in separate structs, you can use JSON as an intermediary in your merge function to abstract away all the reflect-ing you have in your example.
// merges two structs, where a's values take precendence over b's values (a's values will be kept over b's if each field has a value)
func merge(a, b interface{}) interface{} {
jb, err := json.Marshal(b)
if err != nil {
fmt.Println("Marshal error b:", err)
}
err = json.Unmarshal(jb, &a)
if err != nil {
fmt.Println("Unmarshal error b-a:", err)
}
return a
}
All together in a working example: https://play.golang.org/p/5YO2HCi8f0N
I have two different struct as mentioned below A abd B and two process functions. Is there any way by means of which i can write a common function to generate the map[string]struct for the both the struct. Moreover, is there any way using reflection given the struct name i can create the object of the same?
type A struct {
name string
// more fields
}
type B struct {
name string
// more fields
}
func ProcessA(input []A) map[string]A {
output := make(map[string]A)
for _, v := range input {
output[v.name] = v
}
return output
}
func ProcessB(input []B) map[string]B {
output := make(map[string]B)
for _, v := range input {
output[v.name] = v
}
return output
}
Idiomatic way in Go would be to use interface.
type Named interface {
Name() string
}
type letter struct {
name string
}
func (l letter) Name() string {
return l.name
}
type A struct {
letter
// more fields
}
type B struct {
letter
// more fields
}
func ProcessNameds(input []Named) map[string]Named {
output := make(map[string]Named, len(input))
for _, v := range input {
output[v.Name()] = v
}
return output
}
Well, see if something like this would help:
package main
import (
"fmt"
"strconv"
)
type A struct {
name string
// more fields
}
type B struct {
name string
// more fields
}
func Process(x interface{}) interface{} {
ma := make(map[string]int)
mb := make(map[string]string)
if x == nil {
return nil
} else if a, ok := x.([]A); ok {
fmt.Printf("Type A argument passed %s\n", x)
ma[a[0].name] = 1
ma[a[1].name] = 2
return ma //you can return whatever type you want here
} else if b, ok := x.([]B); ok {
fmt.Printf("Type B argument passed %s\n", x)
mb[b[0].name] = "a"
mb[b[1].name] = "b"
return mb //you can return whatever type you want here
} else {
panic(fmt.Sprintf("Unexpected type %T: %v", x, x))
}
return nil
}
func main() {
a := make([]A, 5)
for i := 0; i < len(a); i++ {
a[i].name = strconv.Itoa(i) + "A"
}
b := make([]B, 7)
for i := 0; i < len(b); i++ {
b[i].name = strconv.Itoa(i) + "B"
}
fmt.Println(Process(a))
fmt.Println(Process(b))
//Uncomment line below to see the panic
//fmt.Println(Process(8))
}
https://play.golang.org/p/irdCsbpvUv_t
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.
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
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.