structure with nested maps golang - struct

Hi I'm new to go and was trying to figure out how maps work.
I have made up a little test program and can't seem to get it to work.
What I'm doing wrong?
package main
import (
"fmt"
)
type Stats struct {
cnt int
category map[string]Events
}
type Events struct {
cnt int
event map[string]Event
}
type Event struct {
value int64
}
func main() {
stats := new(Stats)
stats.cnt = 33
stats.category["aa"].cnt = 66
stats.category["aa"].event["bb"].value = 99
fmt.Println(stats.cnt, stats.category["aa"].event["bb"].value)
}

There are couple of issues with the code:
Map needs to be initialized using make function. Currently they are nil
Return value from map is non-addressable, this because if map is growing it needs to relocated which will cause memory address to change. Hence we need to extract value explicitly from map to a variable, update it and assigning it back.
Use pointer
I have updated the solution to show both updated it value returned and assigning it back and pointer.
http://play.golang.org/p/lv50AONXyU
package main
import (
"fmt"
)
type Stats struct {
cnt int
category map[string]Events
}
type Events struct {
cnt int
event map[string]*Event
}
type Event struct {
value int64
}
func main() {
stats := new(Stats)
stats.cnt = 33
stats.category = make(map[string]Events)
e, f := stats.category["aa"]
if !f {
e = Events{}
}
e.cnt = 66
e.event = make(map[string]*Event)
stats.category["aa"] = e
stats.category["aa"].event["bb"] = &Event{}
stats.category["aa"].event["bb"].value = 99
fmt.Println(stats)
fmt.Println(stats.cnt, stats.category["aa"].event["bb"].value)
}

Adding this as a different approach to the problem:
type Stats struct {
cnt int
categories map[string]*Events
}
func (s *Stats) Category(n string) (e *Events) {
if s.categories == nil {
s.categories = map[string]*Events{}
}
if e = s.categories[n]; e == nil {
e = &Events{}
s.categories[n] = e
}
return
}
type Events struct {
cnt int
events map[string]*Event
}
func (e *Events) Event(n string) (ev *Event) {
if e.events == nil {
e.events = map[string]*Event{}
}
if ev = e.events[n]; ev == nil {
ev = &Event{}
e.events[n] = ev
}
return
}
type Event struct {
value int64
}
func main() {
var stats Stats
stats.cnt = 33
stats.Category("aa").cnt = 66
stats.Category("aa").Event("bb").value = 99
fmt.Println(stats)
fmt.Println(stats.cnt, stats.Category("aa").Event("bb").value)
}
playground

There are a few issues with your approach.
You aren't initializing you maps. You need to create them first.
Maps return copies of their values. So when you pull out "aa" and modify it, you are getting a copy of "aa", changing it, then throwing it away. You need to put it back in the map, or use pointers.
Here's a working example (non-pointer version) on Play.
Notice the construction of the maps, and the re-assignment back to the map when modifying a value.
package main
import (
"fmt"
)
type Stats struct {
cnt int
category map[string]Events
}
type Events struct {
cnt int
event map[string]Event
}
type Event struct {
value int64
}
func main() {
stats := &Stats{category: map[string]Events{}}
stats.cnt = 33
tmpCat, ok := stats.category["aa"]
if !ok {
tmpCat = Events{event: map[string]Event{}}
}
tmpCat.cnt = 66
tmpEv := tmpCat.event["bb"]
tmpEv.value = 99
tmpCat.event["bb"] = tmpEv
stats.category["aa"] = tmpCat
fmt.Println(stats.cnt, stats.category["aa"].event["bb"].value)
}

Related

How to compare a previous list and updated a field in multi thread

I have a local cache where I store the runner's lap info, I need to show if the runner's current lap was better or worse than the current lap, while displaying the current lap information.
data class RunInfo(
val runnerId: String,
val lapTime: Double,
var betterThanLastLap: BETTERTHANLASTLAP
)
enum class BETTERTHANLASTLAP {
NA, YES, NO
}
object RunDB {
private var listOfRunners: MutableList<RunInfo> =
java.util.Collections.synchronizedList(mutableListOf())
private var previousList: MutableList<RunInfo> = mutableListOf()
fun save(runList: MutableList<RunInfo>) {
previousList = listOfRunners.toMutableList()
listOfRunners.clear()
listOfRunners.addAll(runList)
listOfRunners.forEach { runner ->
previousList.forEach { previousLap ->
if (runner.runnerId == previousLap.runnerId) {
runner.betterThanLastLap =
when {
previousLap.lapTime == 0.0 -> BETTERTHANLASTLAP.NA
runner.lapTime >= previousLap.lapTime -> BETTERTHANLASTLAP.YES
else -> BETTERTHANLASTLAP.NO
}
}
}
}
}
}
This seems to do the job, but often I get concurrent modification exception. Is there a better way of solving this problem?
I don't recommend combining mutable lists with read-write var properties. Making it mutable in two different ways creates ambiguity and is error prone. Since you're just clearing and replacing the list contents, I would make it a read-only list and a read-write property.
You need to synchronize the whole function so it can only be executed once at a time.
object RunDB {
private var listOfRunners: List<RunInfo> = listOf()
private var previousList: List<RunInfo> = listOf()
fun save(runList: List<RunInfo>) {
sychronized(this) {
previousList = listOfRunners.toList()
listOfRunners = runList.toList()
listOfRunners.forEach { runner ->
previousList.forEach { previousLap ->
if (runner.runnerId == previousLap.runnerId) {
runner.betterThanLastLap =
when {
previousLap.lapTime == 0.0 -> BETTERTHANLASTLAP.NA
runner.lapTime >= previousLap.lapTime -> BETTERTHANLASTLAP.YES
else -> BETTERTHANLASTLAP.NO
}
}
}
}
}
}
}
It also feels error prone to have a mutable data class in these lists that you're copying and shuffling around. I recommend making it immutable:
data class RunInfo(
val runnerId: String,
val lapTime: Double,
val betterThanLastLap: BETTERTHANLASTLAP
)
object RunDB {
private var listOfRunners: List<RunInfo> = listOf()
private var previousList: List<RunInfo> = listOf()
fun save(runList: List<RunInfo>) {
sychronized(this) {
previousList = listOfRunners.toList()
listOfRunners = runList.map { runner ->
val previousLap = previousList.find { runner.runnerId == previousLap.runnerId }
runner.copy(betterThanLastLap = when {
previousLap == null || previousLap.lapTime == 0.0 -> BETTERTHANLASTLAP.NA
runner.lapTime >= previousLap.lapTime -> BETTERTHANLASTLAP.YES
else -> BETTERTHANLASTLAP.NO
})
}
}
}
}

Call functions with special prefix/suffix

I have a package named "seeder":
package seeder
import "fmt"
func MyFunc1() {
fmt.Println("I am Masood")
}
func MyFunc2() {
fmt.Println("I am a programmer")
}
func MyFunc3() {
fmt.Println("I want to buy a car")
}
Now I want to call all functions with MyFunc prefix
package main
import "./seeder"
func main() {
for k := 1; k <= 3; k++ {
seeder.MyFunc1() // This calls MyFunc1 three times
}
}
I want something like this:
for k := 1; k <= 3; k++ {
seeder.MyFunc + k ()
}
and this output:
I am Masood
I am a programmer
I want to buy a car
EDIT1:
In this example, parentKey is a string variable which changed in a loop
for parentKey, _ := range uRLSjson{
pppp := seeder + "." + strings.ToUpper(parentKey)
gorilla.HandleFunc("/", pppp).Name(parentKey)
}
But GC said:
use of package seeder without selector
You can't get a function by its name, and that is what you're trying to do. The reason is that if the Go tool can detect that a function is not referred to explicitly (and thus unreachable), it may not even get compiled into the executable binary. For details see Splitting client/server code.
With a function registry
One way to do what you want is to build a "function registry" prior to calling them:
registry := map[string]func(){
"MyFunc1": MyFunc1,
"MyFunc2": MyFunc2,
"MyFunc3": MyFunc3,
}
for k := 1; k <= 3; k++ {
registry[fmt.Sprintf("MyFunc%d", k)]()
}
Output (try it on the Go Playground):
Hello MyFunc1
Hello MyFunc2
Hello MyFunc3
Manual "routing"
Similar to the registry is inspecting the name and manually routing to the function, for example:
func callByName(name string) {
switch name {
case "MyFunc1":
MyFunc1()
case "MyFunc2":
MyFunc2()
case "MyFunc3":
MyFunc3()
default:
panic("Unknown function name")
}
}
Using it:
for k := 1; k <= 3; k++ {
callByName(fmt.Sprintf("MyFunc%d", k))
}
Try this on the Go Playground.
Note: It's up to you if you want to call the function identified by its name in the callByName() helper function, or you may choose to return a function value (of type func()) and have it called in the caller's place.
Transforming functions to methods
Also note that if your functions would actually be methods of some type, you could do it without a registry. Using reflection, you can get a method by name: Value.MethodByName(). You can also get / enumerate all methods without knowing their names using Value.NumMethod() and Value.Method() (also see Type.NumMethod() and Type.Method() if you need the name of the method or its parameter types).
This is how it could be done:
type MyType int
func (m MyType) MyFunc1() {
fmt.Println("Hello MyFunc1")
}
func (m MyType) MyFunc2() {
fmt.Println("Hello MyFunc2")
}
func (m MyType) MyFunc3() {
fmt.Println("Hello MyFunc3")
}
func main() {
v := reflect.ValueOf(MyType(0))
for k := 1; k <= 3; k++ {
v.MethodByName(fmt.Sprintf("MyFunc%d", k)).Call(nil)
}
}
Output is the same. Try it on the Go Playground.
Another alternative would be to range over an array of your functions
package main
import (
"fmt"
)
func MyFunc1() {
fmt.Println("I am Masood")
}
func MyFunc2() {
fmt.Println("I am a programmer")
}
func MyFunc3() {
fmt.Println("I want to buy a car")
}
func main() {
for _, fn := range []func(){MyFunc1, MyFunc2, MyFunc3} {
fn()
}
}

implementation interfaces in golang

I want to implement the interface shown below. I don't know how to begin. Can someone show me how the functions should be implemented?
package interval
package main
type Interval interface {
contains(r float64) bool // if r is in x, then true
average(Y Intervall) (Intervall, error)
String() string //cast interval"[a,b]" to [a,b]
completecontains(Y Intervall) bool //if y is completely in x, give true
New(a, b float64) Intervall
//var a int
}
type Complex struct {
first int
}
func (c Complex) contains(r float64) bool {
if a <= r <= b {
return true
} else {
return false
}
}
func (c Complex) String() string {
return "a"
}
func (c Complex) length() float64 {
return 2.3
}
func main() {
}
I can't really tell what you are actually trying to do here, but there were several issues with the code
a and b were not defined, I added them to complex to get it to compile
a <= r <= b is not valid in go, changed that
You had a main, so I assume that you meant this to be the runnable app. Package needs to be called "main" for it to be directly runnable.
May not be what you want, but it now compiles and runs (but doesn't do anything since main is empty)
Here it is on play
package main
//import "fmt"
type Intervall interface {
contains(r float64) bool // if r is in x, then true
average(Y Intervall) (Intervall, error)
String() string //cast interval"[a,b]" to [a,b]
completecontains(Y Intervall) bool //if y is completely in x, give true
New(a, b float64) Intervall
}
type Complex struct {
first int
a float64
b float64
}
func (c Complex) contains(r float64) bool {
if c.a <= r && r <= c.b {
return true
} else {
return false
}
}
func (c Complex) String() string {
return "a"
}
func (c Complex) length() float64 {
return 2.3
}
func main() {
}
Not sure why the concrete interval is called "Complex" or what the average of two intervals might be, but this is as close as I can get. Also, not sure what the benefit of using an interface is here.
http://play.golang.org/p/sxFRkJZCFa
package main
import "fmt"
type Interval interface {
Contains(r float64) bool
Average(y Interval) (Interval, error)
String() string
CompletelyContains(y Interval) bool
CompletelyContainedBy(y Interval) bool
}
type Complex struct {
a, b float64
}
func (c Complex) Contains(r float64) bool {
return c.a <= r && r <= c.b
}
func (c Complex) Average(y Interval) (Interval, error) {
return nil, fmt.Errorf("What the heck is the average of two intervals?")
}
func (c Complex) CompletelyContains(y Interval) bool {
return y.CompletelyContainedBy(c)
}
func (c Complex) CompletelyContainedBy(y Interval) bool {
return y.Contains(c.a) && y.Contains(c.b)
}
func (c Complex) String() string {
return fmt.Sprintf("[%v,%v]", c.a, c.b)
}
func main() {
var x Interval = Complex{a: 1, b: 5.1}
var y Interval = Complex{a: 1.3, b: 5}
fmt.Println("x contains 3:", x.Contains(3))
fmt.Println("x completely contains y:", x.CompletelyContains(y))
avg, err := x.Average(y)
fmt.Println("Average of x and y:", avg, "with error:", err)
fmt.Println("x:", x)
}
Edit: Here's a sillily complex way of implementing "Average" the way you want it. The complexity comes from avoiding directly accessing y.a and y.b, which would defeat the purpose of using an interface (if there is one).
http://play.golang.org/p/Tc5YCciLWq

How to gracefully implement EventEmitter in Swift

I am writing a hiredis binding to Swift and working on the async API part.
I would like to have something similar to EventEmitter in Node.js.
objectToBeListened.on('event', (data) => { ... })
objectToBeListened.emit('event')
Namely I hope only one "on" and one "emit" function for every class I have.
I currently use enum for all event types and switch in "on" function. An extra struct which stores all callback functions is introduced.
I could not implement an universal "emit" function: I just glanced the Generics part of Swift. But is it ever possible? It seems that Swift doesn't have variadic template.
Anyway, my prototype code is really ugly and hard to maintain. Is there any better way to implement an EventEmitter gracefully?
class EEProto {
var A: Int
var B: Double
typealias EventChangeA = (Int, Int) -> Void
typealias EventChangeB = (Double, Double) -> Void
typealias EventChanged = () -> Void
struct RegisteredEvent {
var eventChangeA: EventChangeA[]
var eventChangeB: EventChangeB[]
var eventChanged: EventChanged[]
}
enum EventType {
case changeA(EventChangeA[])
case changeB(EventChangeB[])
case changed(EventChanged[])
}
var registeredEvents: RegisteredEvent
init (A: Int, B: Double) {
self.A = A
self.B = B
registeredEvents = RegisteredEvent(eventChangeA: [], eventChangeB: [], eventChanged: [])
}
func on (event: EventType) {
switch event {
case .changeA(let events):
registeredEvents.eventChangeA += events
case .changeB(let events):
registeredEvents.eventChangeB += events
case .changed(let events):
registeredEvents.eventChanged += events
default:
assert("unhandled event type | check your code")
break
}
}
func resetEvents (eventType: EventType) {
switch eventType {
case .changeA:
registeredEvents.eventChangeA = []
case .changeB:
registeredEvents.eventChangeA = []
case .changed:
registeredEvents.eventChangeA = []
default:
assert("unhandled event type | check your code")
break
}
}
func setA (newA: Int) {
let oldA = A
A = newA
for cb in registeredEvents.eventChangeA {
cb(oldA, newA)
}
for cb in registeredEvents.eventChanged {
cb()
}
}
func setB (newB: Double) {
let oldB = B
B = newB
for cb in registeredEvents.eventChangeB {
cb(oldB, newB)
}
for cb in registeredEvents.eventChanged {
cb()
}
}
}
var inst = EEProto(A: 10, B: 5.5)
inst.on(EEProto.EventType.changeA([{
println("from \($0) to \($1)")
}]))
inst.on(EEProto.EventType.changeB([{
println("from \($0) to \($1)")
}]))
inst.on(EEProto.EventType.changed([{
println("value changed")
}]))
inst.setA(10)
inst.setB(3.14)
You can use a library like FlexEmit. It works very similar to the EventEmitter in NodeJS.
Basically you define your events as swift types (these can be any struct, enum, class, etc.):
struct EnergyLevelChanged {
let newEnergyLevel: Int
init(to newValue: Int) { newEnergyLevel = newValue }
}
struct MovedTo {
let x, y: Int
}
Then you create an emitter and add event listeners for different types of events you want to listen for:
let eventEmitter = Emitter()
eventEmitter.when { (newLocation: MovedTo) in
print("Moved to coordinates \(newLocation.x):\(newLocation.y)")
}
eventEmitter.when { (event: EnergyLevelChanged) in
print("Changed energy level to", event.newEnergyLevel)
}
And finally you send your events using a simple emit function
eventEmitter.emit(EnergyLevelChanged(to: 60)) // prints "Changed energy level to 60"
eventEmitter.emit(MovedTo(x: 0, y: 0)) // prints "Moved to coordinates 0:0"

How to find out element position in slice?

How does one determine the position of an element present in slice?
I need something like the following:
type intSlice []int
func (slice intSlice) pos(value int) int {
for p, v := range slice {
if (v == value) {
return p
}
}
return -1
}
Sorry, there's no generic library function to do this. Go doesn't have a straight forward way of writing a function that can operate on any slice.
Your function works, although it would be a little better if you wrote it using range.
If you happen to have a byte slice, there is bytes.IndexByte.
You can create generic function in idiomatic go way:
func SliceIndex(limit int, predicate func(i int) bool) int {
for i := 0; i < limit; i++ {
if predicate(i) {
return i
}
}
return -1
}
And usage:
xs := []int{2, 4, 6, 8}
ys := []string{"C", "B", "K", "A"}
fmt.Println(
SliceIndex(len(xs), func(i int) bool { return xs[i] == 5 }),
SliceIndex(len(xs), func(i int) bool { return xs[i] == 6 }),
SliceIndex(len(ys), func(i int) bool { return ys[i] == "Z" }),
SliceIndex(len(ys), func(i int) bool { return ys[i] == "A" }))
You could write a function;
func indexOf(element string, data []string) (int) {
for k, v := range data {
if element == v {
return k
}
}
return -1 //not found.
}
This returns the index of a character/string if it matches the element. If its not found, returns a -1.
There is no library function for that. You have to code by your own.
Go supports generics as of version 1.18, which allows you to create a function like yours as follows:
func IndexOf[T comparable](collection []T, el T) int {
for i, x := range collection {
if x == el {
return i
}
}
return -1
}
If you want to be able to call IndexOf on your collection you can alternatively use #mh-cbon's technique from the comments.
You can just iterate of the slice and check if an element matches with your element of choice.
func index(slice []string, item string) int {
for i := range slice {
if slice[i] == item {
return i
}
}
return -1
}
Since Go 1.18 you can also use the experimental generic slices package from https://pkg.go.dev/golang.org/x/exp/slices like this:
package main
import "golang.org/x/exp/slices"
func main() {
s := []int{1,2,3,4,5}
wanted := 3
idx := slices.Index(s, wanted)
fmt.Printf("the index of %v is %v", wanted, idx)
}
It will return -1, if wanted is not in the slice. Test it at the playground.
This is my preferred way, since this might become part of the standard library someday.
Another option is to sort the slice using the sort package, then search for the thing you are looking for:
package main
import (
"sort"
"log"
)
var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}
func main() {
data := ints
a := sort.IntSlice(data[0:])
sort.Sort(a)
pos := sort.SearchInts(a, -784)
log.Println("Sorted: ", a)
log.Println("Found at index ", pos)
}
prints
2009/11/10 23:00:00 Sorted: [-5467984 -784 0 0 42 59 74 238 905 959 7586 7586 9845]
2009/11/10 23:00:00 Found at index 1
This works for the basic types and you can always implement the sort interface for your own type if you need to work on a slice of other things. See http://golang.org/pkg/sort
Depends on what you are doing though.
I had the same issue few months ago and I solved in two ways:
First method:
func Find(slice interface{}, f func(value interface{}) bool) int {
s := reflect.ValueOf(slice)
if s.Kind() == reflect.Slice {
for index := 0; index < s.Len(); index++ {
if f(s.Index(index).Interface()) {
return index
}
}
}
return -1
}
Use example:
type UserInfo struct {
UserId int
}
func main() {
var (
destinationList []UserInfo
userId int = 123
)
destinationList = append(destinationList, UserInfo {
UserId : 23,
})
destinationList = append(destinationList, UserInfo {
UserId : 12,
})
idx := Find(destinationList, func(value interface{}) bool {
return value.(UserInfo).UserId == userId
})
if idx < 0 {
fmt.Println("not found")
} else {
fmt.Println(idx)
}
}
Second method with less computational cost:
func Search(length int, f func(index int) bool) int {
for index := 0; index < length; index++ {
if f(index) {
return index
}
}
return -1
}
Use example:
type UserInfo struct {
UserId int
}
func main() {
var (
destinationList []UserInfo
userId int = 123
)
destinationList = append(destinationList, UserInfo {
UserId : 23,
})
destinationList = append(destinationList, UserInfo {
UserId : 123,
})
idx := Search(len(destinationList), func(index int) bool {
return destinationList[index].UserId == userId
})
if idx < 0 {
fmt.Println("not found")
} else {
fmt.Println(idx)
}
}
Another option if your slice is sorted is to use SearchInts(a []int, x int) int which returns the element index if it's found or the index the element should be inserted at in case it is not present.
s := []int{3,2,1}
sort.Ints(s)
fmt.Println(sort.SearchInts(s, 1)) // 0
fmt.Println(sort.SearchInts(s, 4)) // 3
https://play.golang.org/p/OZhX_ymXstF

Resources