Static Initialization in Go? - static

I'm currently working on the Go Lang tutorial, but ran into problem with one of the exercises:
https://tour.golang.org/methods/23
The exercise has me implement a ROT13 cipher. I decided to implement the cipher using a map from a byte to its rotated value but I'm not sure of the best way to initialize this map. I don't want to initialize the map using a literal, but would prefer to do it programmatically by looping through an alphabet and setting (key, value) pairs within the loop. I would also like the map to only be accessible from Rot13Reader struct/object and have all instances(?) share the same map (rather than one copy per Rot13Reader).
Here's my current working Go program:
package main
import (
"io"
"os"
"strings"
)
type rot13Reader struct {
r io.Reader
}
var rot13Map = map[byte]byte{}
func (rotr *rot13Reader) Read(p []byte) (int, error) {
n, err := rotr.r.Read(p)
for i := 0; i < n; i++ {
if sub := rot13Map[p[i]]; sub != byte(0) {
p[i] = sub
}
}
return n, err
}
func main() {
func() {
var uppers = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
var lowers = []byte("abcdefghijklmnopqrstuvwxyz")
var init = func (alphabet []byte) {
for i, char := range alphabet {
rot13_i := (i + 13) % 26
rot13Map[char] = alphabet[rot13_i]
}
}
init(uppers)
init(lowers)
}()
s := strings.NewReader("Lbh penpxrq gur pbqr!")
r := rot13Reader{s}
io.Copy(os.Stdout, &r)
}
Here are the problems I have with this:
I don't want to have to prepare rot13Map in main()
I don't want rot13Map to be in global scope.
I don't want each copy of a rot13Reader to have a separate rot13Map
Is there a way to achieve what I want in Go?

In order to do this, I would make a rot13 package. You can programmatically create the map in an init() function and provide it as a package level global to all your rot13 decoders. The init function runs when your package is imported.
Because Rot13Reader is the only type in the package, it is the only one able to access your map.
WARNING: All code untested.
package rot13
import (
"io"
)
var rot13Map = map[byte]byte{}
func init() {
var uppers = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
var lowers = []byte("abcdefghijklmnopqrstuvwxyz")
var init = func(alphabet []byte) {
for i, char := range alphabet {
rot13_i := (i + 13) % 26
rot13Map[char] = alphabet[rot13_i]
}
}
init(uppers)
init(lowers)
}
type Reader struct {
r io.Reader
}
func (rotr Reader) Read(p []byte) (int, error) {
n, err := rotr.r.Read(p)
for i := 0; i < n; i++ {
if sub := rot13Map[p[i]]; sub != byte(0) {
p[i] = sub
}
}
return n, err
}
Obviously, you can't make another package in the go tour. You are stuck with rot13Map being accessible by main. You will need to run Go locally to get the separation you want.

For the sake of completeness: For initialization work besides of the init function in a package there is sync.Once, which runs a supplied function only once.
You create an Once object and call Do with your function on it. As long as the state of the Once
object is not changed, the supplied function will only be called once.
Example:
import "sync"
var readerInitOnce sync.Once
func (rotr *rot13Reader) Read(p []byte) (int, error) {
readerInitOnce.Do(initRot13Map)
...
}

I would simplify your code and use an init function. For example,
package main
import (
"io"
"os"
"strings"
)
type rot13Reader struct {
r io.Reader
}
func newRot13Map() map[byte]byte {
n := byte('Z' - 'A' + 1)
rot13 := make(map[byte]byte, 2*n)
for ltr := byte(0); ltr < n; ltr++ {
sub := (ltr + 13) % n
rot13[ltr+'A'] = sub + 'A'
rot13[ltr+'a'] = sub + 'a'
}
return rot13
}
var rot13Map map[byte]byte
func init() {
rot13Map = newRot13Map()
}
func (rotr *rot13Reader) Read(p []byte) (int, error) {
n, err := rotr.r.Read(p)
for i, ltr := range p[:n] {
if sub, ok := rot13Map[ltr]; ok {
p[i] = sub
}
}
return n, err
}
func main() {
s := strings.NewReader("Lbh penpxrq gur pbqr!")
r := rot13Reader{s}
io.Copy(os.Stdout, &r)
}
Output:
You cracked the code!

Related

How to store struct with map into an Array in the go language

I made a package that looks like this...
package foo
type Foo struct {
num int
aMap map[int](int)
}
func MakeFoo() BookState {
return Foo{
num: -1,
aMap: make(map[int](int)),
}
}
I'm processing rows of a file like this
nrows :=100
arrayFoo = make([]Foo, nrows)
Foo = foo.MakeFoo()
count := 0
for int i=0; i < nrows; i++ {
row = myWrappedReader.ReadLine()
foo.num = i
foo.aMap[key] += row.otherNum
arrayFoo[i] = foo
}
But then when I go to check the arrayFoo at the end I have something that looks like this
[{num:1, aMap:{/*final state*/}, {num:2, aMap:{/*final state*/}, ...]
So the integer is updating but I need a copy of aMap to be stored instead of just the pointer to aMap.
Update:
Here's a playground.
Update2:
Here's a version that works. My class is quite a bit more complicated than this so I think I'll write a helper function in package foo that clone it.
Is there a easier way to copy maps or do most people do that?
Anything requiring a deep copy, as mentioned in "Is there a built in function in go for making copies of arbitrary maps?", would involve a dedicated function.
Example in this gist:
package deepcopy
import (
"bytes"
"encoding/gob"
)
func init() {
gob.Register(map[string]interface{}{})
}
// Map performs a deep copy of the given map m.
func Map(m map[string]interface{}) (map[string]interface{}, error) {
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
dec := gob.NewDecoder(&buf)
err := enc.Encode(m)
if err != nil {
return nil, err
}
var copy map[string]interface{}
err = dec.Decode(&copy)
if err != nil {
return nil, err
}
return copy, nil
}
Based on the suggestion of mkopriva replacing the line foo.aMap[key] += i with foo.aMap = map[string]int{"key": foo.aMap[key] + i}
package main
import (
"fmt"
)
type Foo struct {
num int
aMap map[string](int)
}
func MakeFoo() Foo {
return Foo{
num: -1,
aMap: make(map[string](int)),
}
}
func main() {
foo := MakeFoo()
key := "tmp"
foo.aMap[key] = 0
fmt.Println(foo)
arrayFoo := make([]Foo, 10)
for i := 0; i < 10; i++ {
foo.num = i
foo.aMap = map[string]int{"key": foo.aMap[key] + i}
arrayFoo[i] = foo
}
fmt.Println(arrayFoo)
}
Output:
{-1 map[tmp:0]}
[{0 map[key:0]} {1 map[key:1]} {2 map[key:2]} {3 map[key:3]} {4 map[key:4]} {5 map[key:5]} {6 map[key:6]} {7 map[key:7]} {8 map[key:8]} {9 map[key:9]}]

Pass a slice of 2d int array without knowing the length of columns

In the function takeinput if i remove the 3 i get an error. My question what to do if i want to use this function to take in input for a different array whose column length is different.
package main
import ("fmt")
func takeinput(in [][3]int){
for i:=0;i<3;i++{
for j:=0;j<3;j++ {
fmt.Scanf("%d",&in[i][j])
}
}
}
func main(){
var a[3][3]int
fmt.Println("Enter the value for matrix one")
takeinput(a[:])
for i:=0;i<3;i++{
for j:=0;j<3;j++{
fmt.Printf("%d\t",a[i][j])
}
fmt.Println()
}
fmt.Println()
}
The error i get if i remove the 3 in input function.
# command-line-arguments
./matrix.go:19:13: cannot use a[:] (type [][3]int) as type [][]int in argument to takeinput
Use slice of slice instead, try this:
package main
import (
"fmt"
)
func takeinput(a [][]int) {
for i := range a {
for j := range a[i] {
fmt.Scanf("%d", &a[i][j])
}
}
}
func main() {
a := make([][]int, 3)
for i := range a {
a[i] = make([]int, 3)
}
fmt.Println("Enter the value for matrix one")
takeinput(a)
for i := range a {
for j := range a[i] {
fmt.Printf("%d\t", a[i][j])
}
fmt.Println()
}
fmt.Println()
}

Refactor code to use a single channel in an idiomatic way

I have the following code:
package main
import (
"fmt"
"time"
)
type Response struct {
Data string
Status int
}
func main() {
var rc [10]chan Response
for i := 0; i < 10; i++ {
rc[i] = make(chan Response)
}
var responses []Response
for i := 0; i < 10; i++ {
go func(c chan<- Response, n int) {
c <- GetData(n)
close(c)
}(rc[i], i)
}
for _, resp := range rc {
responses = append(responses, <-resp)
}
for _, item := range responses {
fmt.Printf("%+v\n", item)
}
}
func GetData(n int) Response {
time.Sleep(time.Second * 5)
return Response{
Data: "adfdafcssdf4343t43gf3jn4jknon239nwcwuincs",
Status: n,
}
}
Can you tell me which would be the right way to accomplish the same goal but using a single channel?
Since you can write different array and slice elements concurrently, you don't need any channels in your case. For details, see Can I concurrently write different slice elements.
Just launch your goroutines, and have them write in the appropriate array (or slice) elements. Use a sync.WaitGroup to wait for all to complete:
wg := &sync.WaitGroup{}
var responses [10]Response
for i := range responses {
wg.Add(1)
go func(n int) {
defer wg.Done()
responses[n] = GetData(n)
}(i)
}
wg.Wait()
for _, item := range responses {
fmt.Printf("%+v\n", item)
}
This outputs the same as your code. Try it on the Go Playground.
Also see related: How to collect values from N goroutines executed in a specific order?

Pass a result from goroutine to a variable inside the loop

At the code below how to assign a result from slowExternalFunction to a proper person? It can be done via channels and just for clarity I defined that slowExternalFunction returns int.
type Person struct {
Id int
Name string
WillDieAt int
}
func slowExternalAPI(i int) int {
time.Sleep(10)
willDieAt := i + 2040
return willDieAt
}
func fastInternalFunction(i int) string {
time.Sleep(1)
return fmt.Sprintf("Ivan %v", i)
}
func main() {
var persons []Person
for i := 0; i <= 100; i++ {
var person Person
person.Id = i
person.Name = fastInternalFunction(i)
go slowExternalAPI(i)
person.WillDieAt = 2050 //should be willDieAt from the slowExternalAPI
persons = append(persons, person)
}
fmt.Printf("%v", persons)
}
https://play.golang.org/p/BRBgtH5ryo
To do it using channels you'll have to refactor your code quite a bit.
Smallest change would be to do the assignment in the goroutine:
go func(){
person.WillDieAt = slowExternalFunction(i)
}()
However, to make this work we'd need to make some other changes as well:
Use an array of pointers so that you can add the person before the assignment finishes.
Implement a wait group so that you wait for all goroutines to finish before printing the results.
Here's the complete main function with the changes:
func main() {
var persons []*Person
var wg sync.WaitGroup
for i := 0; i <= 100; i++{
person := &Person{}
person.Id = i
person.Name = fastInternalFunction(i)
wg.Add(1)
go func(){
person.WillDieAt = slowExternalFunction(i)
wg.Done()
}()
persons = append(persons,person)
}
wg.Wait()
for _, person := range persons {
fmt.Printf("%v ", person )
}
}
Playground: https://play.golang.org/p/8GWYD29inC

Concise and robust way to read a line of space-separated integers in Go

I have been giving HackerRank a try where the problems often require reading lines of integers into arrays (slices).
For many of the problems, my parsing code ends up being larger than the algorithmic meat of the solution. For instance, that was the case in Sherlock and Array
Any ideas on how to concisely parse a space-separated line of integers into a slice? fmt.Scanf doesn't support slices and when using bufio I get long solutions.
Some requirements:
You can only use the standard library.
The solution should be concise, the shorter the better.
Error checks shouldn't be skipped. I know that the input is well defined in HackerRank and you should be able to cut corners, but please don't, it's bad practice.
It should be reasonably efficient.
NOTE:
The parser should only consume a single line and not the full input.
Well, I have done some hackerrank problems too, and here is what I came up with. Typically, problems start with the number of items in the array:
func main() {
var N int
fmt.Scanf("%d", &N)
line := make([]int, N)
for i, _ := range line {
fmt.Scanf("%d", &line[i])
}
// Do something with the values
}
// inputs space separated list of integers, outputs []int64
package main
import (
"bufio"
"fmt"
"strconv"
"strings"
)
func main() {
fmt.Println(parse("100 200 300"))
}
func parse(i string) (o []int64) {
// from https://golang.org/pkg/bufio/#example_Scanner_custom
s := bufio.NewScanner(strings.NewReader(i))
splitter := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
advance, token, err = bufio.ScanWords(data, atEOF)
if err == nil && token != nil {
x, err := strconv.ParseInt(string(token), 10, 32)
if err != nil {
panic(err)
}
o = append(o, x)
}
return
}
s.Split(splitter)
for s.Scan() {
}
return o
}
You can use fmt.Scanf, but you need to keep track of the values you're getting.
// a.go
package main
import (
"fmt"
"io"
)
func main() {
var (
next int
nums []int
)
for {
n, err := fmt.Scanf("%d", &next)
if err == io.EOF {
break
}
if err != nil {
panic(err)
}
if n == 0 {
break
}
nums = append(nums, next)
}
fmt.Printf("%#v\n", nums)
}
$ echo "4 8 15 16 23 42" | go run a.go
[]int{4, 8, 15, 16, 23, 42}
1) read string
2) prepend [ and append ]
3) parse as json into []int?
var input = "1,2,3"
var answer []int
j := []byte(fmt.Sprintf("[%s]",input))
err:= json.Unmarshal(j, &input)
if err != nil {
panic(err)
}
for k,v := range input {
fmt.Printf("Element №%v is %v\n", k,v)
}
also using split strings (https://godoc.org/strings#Split)
and https://godoc.org/strconv#ParseInt
input:= "1,2,3"
temp := strings.Split(input, ",")
var answer []int
for _,v := range temp {
i,err := strconv.ParseInt(v)
if err != nill {
panic(err)
}
answer = append(answer, i)
}
UPD: just found that the numbers are SPACE separated.
So, this code have to do the thing:
input:= "1 2 3"
temp := strings.Split(input, " ")
var answer []int
for _,v := range temp {
i,err := strconv.ParseInt(v)
if err != nill {
panic(err)
}
answer = append(answer, i)
}
func main() {
arr := make([]int, 0)
reader := bufio.NewReaderSize(os.Stdin, 1024*1024)
for {
line, _, err := reader.ReadLine()
if err != nil {
if err == io.EOF {
break
}
panic(err)
}
str := strings.Split(string(line), " ")
for i:=0; i<len(str); i++ {
v, _ := strconv.Atoi(str[i])
arr = append(arr, v)
}
}
fmt.Println(arr)
}
I've used this for those times playing in hackerrank (so concise, but not tested for humans):
func scanInt(n int) []int {
input := make([]int, n)
buffer := make([]interface{}, n)
for i := 0; i < n; i++ {
buffer[i] = &input[i]
}
fmt.Scanln(buffer...)
return input
}

Resources