I have data structure:
type PosList []int
type InvertedIndex struct {
Capacity int
Len int
IndexList []PosList
}
I have problem with Add method:
func (ii *InvertedIndex) Add(posList PosList, docId int) {
if ii.Len == ii.Capacity {
newIndexList := make([]PosList, ii.Len, (ii.Capacity+1)*2)
for i := 0; i < ii.Len; i++ {
newIndexList[i] = make([]int, len(ii.IndexList[i]))
copy(newIndexList[i], ii.IndexList[i])
}
ii.IndexList = newIndexList
}
ii.IndexList = ii.IndexList[0 : ii.Len+2]
ii.IndexList[docId] = posList
return
}
Or, i try something like this:
func (ii *InvertedIndex) Add(posList PosList, docId int) {
if ii.Len == ii.Capacity {
newIndexList := make([]PosList, ii.Len, (ii.Capacity+1)*2)
copy(newIndexList, ii.IndexList)
ii.IndexList = newIndexList
}
ii.IndexList = ii.IndexList[0 : ii.Len+2]
ii.IndexList[docId] = posList
return
}
Both of them don't work, may be someone can explain how can i append a slice to structure like this.
You question is confusing. I assume that you are trying to create a typical inverted index. In which case, you probably want to do something like this:
package main
import "fmt"
type DocId int
type Positions []int
type docIndex struct {
docId DocId
positions Positions
}
type InvertedIndex struct {
docIndexes []docIndex
}
func New() *InvertedIndex {
return &InvertedIndex{}
}
func (ii *InvertedIndex) Add(docId DocId, positions Positions) {
for i, di := range (*ii).docIndexes {
if di.docId == docId {
di.positions = append(di.positions, positions...)
(*ii).docIndexes[i] = di
return
}
}
di := docIndex{
docId: docId,
positions: positions,
}
(*ii).docIndexes = append((*ii).docIndexes, di)
}
func main() {
ii := New()
docId := DocId(11)
positions := Positions{42, 7}
ii.Add(docId, positions)
positions = Positions{21, 4}
ii.Add(docId, positions)
docId = DocId(22)
positions = Positions{84, 14}
ii.Add(docId, positions)
fmt.Printf("%+v\n", *ii)
}
Output:
{docIndexes:[{docId:11 positions:[42 7 21 4]} {docId:22 positions:[84 14]}]}
The statement:
di.positions = append(di.positions, positions...)
appends a slice to a slice.
References:
Appending to and copying slices
Arrays, slices (and strings): The mechanics of 'append'
inverted index
I'm not sure I fully understand what you're doing, however something like this should just work fine, replacing the slice with a map :
type PosList []int
type InvertedIndex struct {
Len int
IndexList map[int]PosList
}
func (ii *InvertedIndex) Add(posList PosList, docId int) {
if ii.IndexList == nil {
ii.IndexList = make(map[int]PosList)
}
if _, ok := ii.IndexList[docId]; ok {
ii.IndexList[docId] = append(ii.IndexList[docId], posList...)
} else {
ii.IndexList[docId] = posList
}
ii.Len = len(ii.IndexList)
}
Related
I have a lot (20+) "Enum Types" of the following form. What I'd like to do is list all the Enum types by name in a struct (see below) and a pointer to a function that returns all of the types. See below for an abbreviated sample.
package main
type Fruit int
const (
unknownFruit Fruit = iota // must be first
Apple
Banana
fruitDone
)
func FruitTypes() []Fruit {
var res []Fruit
for typ := unknownFruit + 1; typ < fruitDone; typ++ {
res = append(res, typ)
}
return res
}
type Car int
const (
unknownCar Car = iota // must be first
BMW
Mercedes
doneCar
)
func CarTypes() []Car {
var res []Car
for typ := unknownCar + 1; typ < doneCar; typ++ {
res = append(res, typ)
}
return res
}
func main() {
enumTypes := []struct {
Name string
Length int
ConvertFunc func(int) string
}{
{Name: "Fruit", Length: int(doneFruit), ConvertFunc: ConvertEnum[Fruit]},
{Name: "Car", Length: int(doneCar), ConvertFunc: ConvertEnum[Car]},
}
for _, enumType := range enumTypes {
fmt.Println(enumType.Name)
for i := 0; i < enumType.Length; i++ {
fmt.Printf(" -- %s", enumType.ConvertFunc(i))
}
}
}
func ConvertEnum[T any](raw int) string {
return fmt.Sprintf("%v", T(raw)) // #2 - This will not convert
}
Unfortunately, I cannot seem to declare the function pointer properly. What's the correct return type?
(As an aside, is there a way to declare an interface for these enum types and/or use generics so that I don't have to have FruitType(), CarType(), PetType()...
=================
UPDATE - thanks to #Woody1193, I feel like I'm much closer. I'm now using the fact that enums are sequential numbers, so I don't really need to pass in any details other than the type so I can cast it back inside the loop (see marker #1 above).
However, in the above, I get:
./main.go:55:64: cannot use EnumType[Fruit] (value of type func(done Fruit) []Fruit) as type func() []int in struct literal
./main.go:56:60: cannot use EnumType[Car] (value of type func(done Car) []Car) as type func() []int in struct literal
./main.go:62:43: too many arguments in call to typ.TypeFunction
=================
Update #2 - I've tried to take a different angle, and just pass in the conversion function, to get it out of the struct. (See above). But now it won't let me cast it :(
./main.go:68:31: cannot convert raw (variable of type int) to type T
The issue you're having here is that neither Car nor Fruit is actually an integer, so TypesFunction will not accept CarTypes or FruitTypes. Generics will not work in this situation because declaring a slice of such objects would require them to all have the same type parameter, which means your code still wouldn't work.
Therefore, your best option is to modify CarTypes and FruitTypes so that they have the same signature, func() []int:
func FruitTypes() []int {
var res []int
for typ := unknownFruit + 1; typ < fruitDone; typ++ {
res = append(res, typ)
}
return res
}
func CarTypes() []int {
var res []int
for typ := unknownCar + 1; typ < doneCar; typ++ {
res = append(res, typ)
}
return res
}
Of course, this will mean that you'll have to use type casting when you want the specific type of enum, but the code will work.
As an aside, you can use generics to generate the function itself:
func EnumType[T ~int](done T) []int {
var res []int
for typ := T(1); typ < done; typ++ {
res = append(res, typ)
}
return res
}
func ConvertEnum[T ~int](raw ...int) []T {
res := make([]T, len(raw))
for i, typ := range raw {
res[i] = T(typ)
}
return res
}
enumTypes := []struct {
Name string
TypesFunction func() []int
}{
{Name: "Fruit", TypesFunction: EnumType[Fruit]},
{Name: "Car", TypesFunction: EnumType[Car]},
}
I want to make a linked list which can hold the values of any type but the linked list must hold values of any one type only.
In general when I am using interfaces for achieving this - any type which implements the interface for the node can be added to the linked list.
I have written an implementation for this where whenever a new key is added to the linked list, the type of the key is checked against the type of the key at the head. I want to understand if this is the correct way of implementing it or is there a better way of doing it.
package main
import (
"errors"
"fmt"
"reflect"
"strings"
)
type MyNode struct {
value int
}
func (node *MyNode) PrintValue() {
fmt.Printf(" %d ", node.value)
}
type llNode struct {
key llNodeInterface
next *llNode
llNodeType reflect.Type
}
type llNodeInterface interface {
PrintValue()
}
type ComplexNode struct {
realValue int
imageValue int
}
func (node *ComplexNode) PrintValue() {
fmt.Printf(" %d + i%d", node.realValue, node.imageValue)
}
// Student type.
type Student struct {
name string
age int
}
// Student implements the PrintValue function - thus llNodeInterface is implemented.
func (node *Student) PrintValue() {
fmt.Printf("Name: %s | Age : %d ", node.name, node.age)
}
// Function which will check the of the new node before adding to the linked
// list. It checks the type of the new key against the type of the key in the
// head. If both are equal then it proceed else return error.
func (head *llNode) AddBeforeHeadTypeCheck(passedKey llNodeInterface) error {
if head.key == nil {
head.key = passedKey
head.llNodeType = reflect.TypeOf(head.key)
} else {
typeOfPassedKey := reflect.TypeOf(passedKey)
if typeOfPassedKey != head.llNodeType {
fmt.Printf("\nUnsupported type for the type %T", passedKey)
return errors.New("Type mistmatch")
}
temp := llNode{key: head.key, next: head.next}
head.key = passedKey
head.next = &temp
}
return nil
}
// Function which will not check the types and will simply add the new node to
// the linked list. Thus linked list will be able to have nodes of multiple
// types.
func (head *llNode) AddBeforeHead(passedKey llNodeInterface) {
if head.key == nil {
head.key = passedKey
head.llNodeType = reflect.TypeOf(head.key)
} else {
temp := llNode{key: head.key, next: head.next}
head.key = passedKey
head.next = &temp
}
}
func (head *llNode) Init() {
head.key = nil
head.next = nil
head.llNodeType = nil
}
// Print the linked list.
func (head *llNode) DisplayLL() {
temp := head
fmt.Printf("\n%s", strings.Repeat("#", 80))
fmt.Printf("\nPrinting the linked list\n")
for {
if temp.key == nil {
fmt.Println("Linked list is empty")
break
} else {
fmt.Printf("\n %T %v ", temp.key, temp.key)
key := temp.key
key.PrintValue()
if temp.next == nil {
break
} else {
temp = temp.next
}
}
}
fmt.Printf("\n%s", strings.Repeat("#", 80))
fmt.Printf("\n\n")
}
func testWithMixedType() {
head := llNode{}
head.Init()
for i := 1; i < 10; i++ {
temp := &ComplexNode{i, i * 10}
head.AddBeforeHeadTypeCheck(temp)
}
temps := &Student{"rishi", 20}
head.AddBeforeHeadTypeCheck(temps) // Will give error.
head.DisplayLL()
}
func testWithComplexNumber() {
head := llNode{}
head.Init()
for i := 1; i < 10; i++ {
temp := &ComplexNode{i, i * 10}
head.AddBeforeHeadTypeCheck(temp)
}
}
func main() {
testWithComplexNumber()
testWithMixedType()
}
The code is working fine - but I want to understand if there is a better or different way of doing this.
Also - what is the performance impact of the current checking of types using the reflect package. Is there a different way of achieving the same thing.
Unsupported type for the type *main.Student
Unsupported type for the type *main.Student
################################################################################
Printing the linked list
*main.ComplexNode &{9 90} 9 + i90
*main.ComplexNode &{8 80} 8 + i80
*main.ComplexNode &{7 70} 7 + i70
*main.ComplexNode &{6 60} 6 + i60
*main.ComplexNode &{5 50} 5 + i50
*main.ComplexNode &{4 40} 4 + i40
*main.ComplexNode &{3 30} 3 + i30
*main.ComplexNode &{2 20} 2 + i20
*main.ComplexNode &{1 10} 1 + i10
################################################################################
Good news, starting from Go 1.18, Generics are now supported in Go.
Following the example from the question, here is a simplified LinkedList using Generics. You can tinker with it at the playground here.
package main
import "fmt"
type MyNode[T any] struct {
next *MyNode[T]
value T
}
type MyLinkedList[T any] struct {
head *MyNode[T]
tail *MyNode[T]
}
func (list *MyLinkedList[T]) Add(t T) *MyLinkedList[T] {
// create node
node := &MyNode[T]{nil, t}
// if first node in list
if list.head == nil {
list.head = node
list.tail = node
} else {
list.tail.next = node
list.tail = list.tail.next
}
return list
}
func (list *MyLinkedList[T]) AddBeforeHead(t T) *MyLinkedList[T] {
node := &MyNode[T]{nil, t}
if list.head != nil {
node.next = list.head
list.head = node
} else {
// make head
list.head = node
list.tail = node
}
return list
}
// display the list
func DisplayList[T any](list *MyLinkedList[T]) string {
var out string = ""
iter := list.head
for iter != nil {
out += fmt.Sprintf("%v -> ", iter.value)
iter = iter.next
}
return out
}
func (list *MyLinkedList[T]) Display() string {
return DisplayList(list)
}
// for printing node value
// you could also implement Stringer
// but this is besides the point, you can ignore
func (node *MyNode[T]) String() string {
return fmt.Sprintf("<MyNode: %v>", node.value)
}
// helper func: create list from array
func CreateLinkedList[T any](arr []T) *MyLinkedList[T] {
list := &MyLinkedList[T]{}
for _, v := range arr {
list.Add(v)
}
return list
}
func main() {
// create a list from array of integers
intArr := []int{10, 20, 30, 40, 50, 60}
list1 := CreateLinkedList(intArr)
// create a list from array of strings
strArr := []string{"foo", "bar", "baz", "faz"}
list2 := CreateLinkedList(strArr)
// test inserting at the beginning
list2.AddBeforeHead("hello")
fmt.Println(list1.Display())
fmt.Println(list2.Display())
}
Some official references covering basics of Generics can be found here:
https://go.dev/doc/tutorial/generics
https://go.dev/blog/intro-generics
https://go.dev/tour/generics/1
You can do it either by using interfaces and runtime checks (as you've discovered), or by using code generation. These are the current options you have in Go for generic programming. The Go team is working to add generics to the language - it's a work in progress, and everyone is free to participate in the discussion. Once generics exist, they will provide the solution you seek here.
As for interfaces vs. code generation, there are the performance implications you've mentioned. Code generation will generate tighter code that doesn't need to do runtime checks for most operations; on the other hand, it adds a bit of complexity to the build process of your project. These are the usual tradeoffs of having something resolved at run-time vs. precomputing things at compile-time.
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 have a program where many functionalities are similar across different structures, however, I end up writing these functions again and again, esp because the variable that are being dealt inside are of different structures.
I have written a sample code here.
In Go Playgroud
package main
import "fmt"
func (a *Match) Add(v Match) {
a.Runs += v.Runs
a.Points += v.Points
}
type Match struct {
Runs uint64
Points uint64
}
func (a *Activity) Add(v Activity) {
a.Walk += v.Walk
a.Jog += v.Jog
}
type Activity struct {
Walk uint64
Jog uint64
}
func GetDailyMatches() map[string]Match {
var dailyMatches map[string]Match
Match1, Match2 := Match{5, 10}, Match{1, 2}
dailyMatches = make(map[string]Match)
dailyMatches["01"] = Match1
dailyMatches["02"] = Match2
dailyMatches["03"] = Match1
dailyMatches["04"] = Match2
return dailyMatches
}
func GetDailyActivities() map[string]Activity {
var dailyActivities map[string]Activity
Activity1, Activity2 := Activity{5, 10}, Activity{1, 2}
dailyActivities = make(map[string]Activity)
dailyActivities["01"] = Activity1
dailyActivities["02"] = Activity2
dailyActivities["03"] = Activity1
dailyActivities["04"] = Activity2
return dailyActivities
}
func main() {
fmt.Println(CalculateMatchSummary("01", "03"))
fmt.Println(CalculateActivitySummary("02", "04"))
fmt.Println(CalculateMatchSummary("01", "03"))
fmt.Println(CalculateActivitySummary("02", "04"))
}
func CalculateMatchSummary(start, end string) (total Match) {
dailyMatches := GetDailyMatches()
for day, value := range dailyMatches {
if day < start {
continue
} else if day > end {
continue
} else {
total.Add(value)
}
}
return
}
func CalculateActivitySummary(start, end string) (total Activity) {
dailyActivities := GetDailyActivities()
for day, value := range dailyActivities {
if day < start {
continue
} else if day > end {
continue
} else {
total.Add(value)
}
}
return
}
If you notice, both Match and Activity has the same functions and same structures, except that internally they are of different structures.
Is there a easy way to make the code more generic (Go generics, which is not there in Go??) in Golang itself.
Go has a pretty package "reflect". You can not do genericity strictly speaking but you can get unification of code for the same behavior.
I've changed your playground a bit : https://play.golang.org/p/bfqZsFOgVQ
The main part :
func AddTwo(a, b interface{}) interface{} {
va := reflect.ValueOf(a)
vb := reflect.ValueOf(b)
res := reflect.New(reflect.TypeOf(a)).Elem()
if va.Kind() != reflect.Struct && vb.Kind() != reflect.Struct {
return nil
}
na, nb := va.NumField(), vb.NumField()
if na != nb {
return nil
}
for i := 0; i < na; i++ {
// additional verification needed here
fa := va.Field(i).Uint()
fb := vb.Field(i).Uint()
fr := fa + fb
res.Field(i).SetUint(fr)
}
return res.Interface()
}
I use reflect to check the fields of the struct I am given. If both are uint64, I can add them reflectively. If your structs contains many uint64, it can add them all !
Note that you must convert the resulting interface to the type of the struct given after calling this function. That is why this is not strictly generic, because the returning type is a interface, and not a Match or Activity.
EDIT: No need even to return a new struct. You can simply update the field of the "a" struct by calling .SetUint() method.
I have following code in Go:
type Foo struct { Id int }
type Bar struct { Id int }
func getIdsFoo(foos []Foo) {
ids = make([]int, len(foos))
// iterate and get all ids to ids array
}
func getIdsBar(bars []Bar) {
ids = make([]int, len(bars))
// iterate and get all ids to ids array
}
Is there a clever way to create a function getIds([]Idable) that can take any struct that have method GetId() implemented?
type Identifiable interface {
GetId() int
}
func GatherIds(ys []Identifiable) []int {
xs := make([]int, 0, len(ys))
for _, i := range ys {
xs = append(xs, i.GetId())
}
return xs
}
sort uses a design patter that might help you.
Create a function that works on an slice-like interface. Then create new types based off of a slice of your concrete types.
Hopefully, the code is more clear than my description. http://play.golang.org/p/TL6yxZZUWT
type IdGetter interface {
GetId(i int) int
Len() int
}
func GetIds(ig IdGetter) []int {
ids := make([]int, ig.Len())
for i := range ids {
ids[i] = ig.GetId(i)
}
return ids
}
type Foo struct{ Id int }
type Bar struct{ Id int }
type FooIdGetter []Foo
func (f FooIdGetter) GetId(i int) int {
return f[i].Id
}
func (f FooIdGetter) Len() int {
return len(f)
}
type BarIdGetter []Bar
func (b BarIdGetter) GetId(i int) int {
return b[i].Id
}
func (b BarIdGetter) Len() int {
return len(b)
}
func main() {
var f = []Foo{{5}, {6}, {7}}
var b = []Bar{{10}, {11}, {12}}
fmt.Println("foo ids:", GetIds(FooIdGetter(f)))
fmt.Println("bar ids:", GetIds(BarIdGetter(b)))
}
There is still a bit more boilerplate than is pleasant, (Go generics... someday). It's greatest advantage is that new methods do not need to be added to Foo, Bar, or any future type you may need to work with.