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(©)
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]}]
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()
}
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?
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
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
}