Indirectly change a value in a struct in Go - go

I have the following code, feel free to offer pointers if you wish:
package main
import (
"fmt"
)
type Grid struct {
rows int
cols int
tiles []Tile
}
type Tile struct {
x int
y int
contents int
}
func (g Grid) AddTile(t Tile) {
g.tiles = append(g.tiles, t)
}
func (g *Grid) Row(num int) []Tile {
numTiles := len(g.tiles)
row := []Tile{}
for i := 0; i < numTiles; i++ {
tile := g.tiles[i]
if (tile.y == num) {
row = append(row, tile)
}
}
return row
}
/*
HERE IS WHERE I NEED HELP
*/
func (g *Grid) SetRow(num, val int) {
row := g.Row(num)
rowLength := len(row)
for i := 0; i < rowLength; i++ {
tile := &row[i]
tile.contents = val
}
}
func (g Grid) Col(num int) []Tile {
numTiles := len(g.tiles)
col := []Tile{}
for i := 0; i < numTiles; i++ {
tile := g.tiles[i]
if (tile.x == num) {
col = append(col, tile)
}
}
return col
}
func MakeTile(x, y int) Tile {
tile := Tile{x: x, y: y}
return tile
}
func MakeGrid(rows, cols int) Grid {
g := Grid{ rows: rows, cols: cols}
for r := 1; r <= rows; r++ {
for c := 1; c <= cols; c++ {
g.tiles = append(g.tiles, MakeTile(r, c))
}
}
return g
}
func main() {
g := MakeGrid(256, 256)
g.SetRow(100, 5)
fmt.Println(g.Row(100))
}
I am doing this, more than anything, as a simple project to help me learn Go. The problem that is have run in to is here
/*
HERE IS WHERE I NEED HELP
*/
func (g *Grid) SetRow(num, val int) {
row := g.Row(num)
rowLength := len(row)
for i := 0; i < rowLength; i++ {
tile := &row[i]
tile.contents = val
}
}
Somewhere it seems like I need to be making a pointer to the actual Tiles that I'm trying to modify. As it is the SetRow function doesn't actually modify anything. What am I doing wrong? Keep in mind I just started learning Go 2 days ago, so this is a learning experience :)

One way to accomplish your goal is to use pointers to tiles throughout the code. Change the Grid tiles field to:
tiles []*Tile
and several related changes through the code.
Also, change all the methods to use pointer receivers. The AddTile method as written in the question discards the modification to the grid on return.
playground example

Related

Why does this goroutine behave like it's call by reference?

I'm trying to learn the basics of Go and I'm a bit confused about the difference between call by value and call by reference in a code snippet I tested.
I tried to solve a coding game puzzle in which a solution for a tic-tac-toe field is to be calculated.
The code I'm using
Because I'm learning Go, I wanted to use a goroutine to test every field of the tic-tac-toe board, check whether this field is the solution and then put a pointer to this field in a channel for the main method to have the result. The code I used looks like this:
package main
import "fmt"
import "os"
var player int = int('O')
var opponent int = int('X')
var empty int = int('.')
type board struct {
fields [][]int
}
func main() {
lines := [3]string {"OO.", "...", "..."}
var b board
b.fillBoard(lines)
fmt.Fprintln(os.Stderr, "input board:")
b.printBoard(true)
resultChannel := make(chan *board)
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
go tryField(b, [2]int{i, j}, resultChannel) // goroutine call that isn't working as expected
}
}
fmt.Fprintln(os.Stderr, "\nresult:")
for i := 0; i < 9; i++ {
resultBoard := <- resultChannel
if (resultBoard != nil) {
resultBoard.printBoard(false)
return
}
}
// fmt.Fprintln(os.Stderr, "Debug messages...")
fmt.Println("false")// Write answer to stdout
}
func tryField(b board, field [2]int, result chan *board) {
b.printBoard(true)
fmt.Fprintln(os.Stderr, "add O to field: ", field)
fmt.Fprint(os.Stderr, "\n")
if (b.fields[field[0]][field[1]] != empty) {
result <- nil
}
b.fields[field[0]][field[1]] = player
if (b.isWon()) {
result <- &b
} else {
result <- nil
}
}
func (b *board) fillBoard(lines [3]string) {
b.fields = make([][]int, 3)
for i := 0; i < 3; i++ {
b.fields[i] = make([]int, 3)
}
for i, line := range lines {
for j, char := range line {
b.fields[i][j] = int(char)
}
}
}
func (b *board) printBoard(debug bool) {
var stream *os.File
if (debug) {
stream = os.Stderr
} else {
stream = os.Stdout
}
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
fmt.Fprint(stream, string(b.fields[i][j]))
}
fmt.Fprint(stream, "\n")
}
}
func (b *board) isWon() bool {
for i := 0; i < 3; i++ {
rowFull := true
colFull := true
for j := 0; j < 3; j++ {
rowFull = rowFull && b.fields[i][j] == player
colFull = rowFull && b.fields[j][i] == player
}
if (rowFull || colFull) {
return true
}
}
diagonal1Full := true
diagonal2Full := true
for i := 0; i < 3; i++ {
diagonal1Full = diagonal1Full && b.fields[i][i] == player
diagonal2Full = diagonal2Full && b.fields[i][2-i] == player
}
if (diagonal1Full ||diagonal2Full) {
return true
}
return false
}
You can run it in the go playground.
The problem
Since the last function in the snippet is declared as func tryField(b board, field [2]int, result chan *board) I assume the board b to be an indipendent copy, each time I call the method, because it's call by value. So changing this board should not affect the other boards in the other goroutines. But unfortunately changing the board in one goroutine does affect the boards in the other goroutines as the output of the programm is the following:
input board:
OO.
...
...
result:
OO.
...
...
add O to field: [1 0]
OO.
O..
...
add O to field: [2 1]
OO.
O..
.O.
As you can see the initial field has two O's at the first and the second col in the first line. Adding an O to the position [1 0] works like expected, but when adding an O to the field [2 1] the there is also an O at [1 0], which was added in the previous goroutine and shouldn't be there since it's call by value.
The question
Why does the code in my snippet behave like it's call by reference although the function doesn't use a pointer?
Thanks in advance !
Slices are references to arrays. When modifying a slice without copying it, the underlaying array will be modified. Therefore, all slices that point to the same underlaying array will see this change.

Idiomatic/Proper Go code refactoring for a UnionFind library

I am practicing a classic algorithm problem in go "number of islands". I want to solve it using unionfind. Although I can tweak and make it work, I would like to know the best way to structure my code.
Here is the main program.
package main
import (
"fmt"
u "practice/leetcode/library/unionfind"
)
type point u.Point
func numIslands(grid [][]byte) int {
res := 0
if grid == nil || grid[0] == nil {
return res
}
m := len(grid)
n := len(grid[0])
num := 0
uf := u.NewUnionFind()
directions := []point{
point{1, 0},
point{-1, 0},
point{0, 1},
point{0, -1},
}
emptyPoint := point{}
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
if grid[i][j] == 1 {
p := point{i, j}
uf.Add(p)
num++
for _, v := range directions {
newx := i + v.X
newy := j + v.Y
if 0 <= newx && newx < m && 0 <= newy && newy < n && grid[newx][newy] == 1 {
newp := point{newx, newy}
if uf.Find(newp) == emptyPoint {
continue
}
uf.Union(p, newp)
num--
}
}
}
}
}
return num
}
func main() {
// expect 1
grid := [][]byte {
{1,1,1,1,0},
{1,1,0,1,0},
{1,1,0,0,0},
{0,0,0,0,0},
}
fmt.Println(numIslands(grid))
// expect 2
grid = [][]byte {
{1,0},
{0,1},
}
fmt.Println(numIslands(grid))
}
Here is the unionfind library I wrote
package unionfind
type Point struct {
X int
Y int
}
type UnionFind struct {
parent map[Point]Point
}
func NewUnionFind() *UnionFind {
parent := make(map[Point]Point)
return &UnionFind{parent}
}
func (uf *UnionFind) Add(c Point) {
if _, ok := uf.parent[c]; ok {
return
}
uf.parent[c] = c
}
func (uf *UnionFind) Find(c Point) Point {
if p, ok := uf.parent[c]; ok {
if p != c {
uf.parent[c] = uf.Find(p)
}
return uf.parent[c]
}
return Point{}
}
func (uf *UnionFind) Union(c1 Point, c2 Point) {
p1 := uf.Find(c1)
p2 := uf.Find(c2)
if p1 != p2 {
uf.parent[p1] = p2
}
}
The problem is when I ran the main program, i got the following errors:
# command-line-arguments
./200_number_of_islands_uf.go:31:15: cannot use p (type point) as type unionfind.Point in argument to uf.Add
./200_number_of_islands_uf.go:38:23: cannot use newp (type point) as type unionfind.Point in argument to uf.Find
./200_number_of_islands_uf.go:38:30: invalid operation: uf.Find(newp) == emptyPoint (mismatched types unionfind.Point and point)
./200_number_of_islands_uf.go:41:21: cannot use p (type point) as type unionfind.Point in argument to uf.Union
./200_number_of_islands_uf.go:41:21: cannot use newp (type point) as type unionfind.Point in argument to uf.Union
The hard requirement I want is:
1.I want to keep the unionfind as a library
2.I need to access the Point struct in the main program
The design requirement I am trying to follow is:
I tried to avoid using an interface for the UnionFind parent map since I can foresee only the Point struct get pass in to the library.
My requirements could be wrong. I am open to suggestions to refactor the code and make it more elegant looking.
When you do this:
type point u.Point
then point is not just an aliased name for u.Point which can be used interchangeably - it's an entirely new type, and one which your uniontype package knows nothing about and therefore will not accept.
So just don't do that, and instead directly use the type the uniontype package provides for you. For example, change:
directions := []point{
point{1, 0},
point{-1, 0},
point{0, 1},
point{0, -1},
}
emptyPoint := point{}
to:
directions := []u.Point{
u.Point{1, 0},
u.Point{-1, 0},
u.Point{0, 1},
u.Point{0, -1},
}
emptyPoint := u.Point{}
and so on.

When I use golang's append function to create a 2D slice, the previous value in the slice changes

Here is my code:
package src
func Subsets(nums []int) [][]int {
var sets = make([][]int, 0)
var t = make([]int, 0)
sets = append(sets, t)
for i := 0; i < len(nums); i++ {
for _, v := range sets {
t = append(v, nums[i])
sets = append(sets, t) }
}
return sets
}
Test data is []int{1,2,3,4,5}
I debug it. found that:
When calculate sets[22], the sets[15] from []int{1,2,3,4} change to []int{1,2,3,5}
What happened.
The problem is that the elements of sets kind of reference the same slice.
You better create a new slice for each element of sets. Appending does not create a new slice.
Here is a fix which copies the previous vector of sets instead of simply extending it.
package src
func Subsets(nums []int) [][]int {
var sets = make([][]int, 0)
var t = make([]int, 0)
sets = append(sets, t)
for i := 0; i < len(nums); i++ {
for _, v := range sets {
t = append([]int(nil), v...) // t is copy of v
t = append(t, nums[i])
sets = append(sets, t)
}
}
return sets
}
Tested here: https://play.golang.org/p/OZ9nN_t3w9D

Mapping bits to int

I'm trying to map a uint64 array bit positions to an int array (see below). BitSet is a []uint64. Below is my code as currently setup. But I am wondering if there could be a std function in golang that can reduce this code. Other language has BitArray or other objects that makes life much easier.
So, in golang, do we have to code this? is there a better to do this?
// Indexes the index positions of '1' bits as an int array
func (b BitSet) Indexes() []int {
// set up masks for bit ANDing
masks := make([]uint64, _BitsPerUint64)
for i := 0; i < _BitsPerUint64; i++ {
masks[i] = (1 << uint(i))
}
// iterate bitset
indexes := make([]int, 0, len(b)*4)
for i := 0; i < len(b); i++ {
for m := 0; m < _BitsPerUint64; m++ {
if masks[m]&b[i] > 0 {
indexes = append(indexes, i*_BitsPerUint64+m)
}
}
}
return indexes
}
func (b BitSet) Indexes() []int {
retval := make([]int, 0, len(b)*64)
for idx, value := range b {
for i := 0; i < 64; i++ {
if value & (1<<uint(i)) != 0 {
retval = append(retval, idx*64 + i)
}
}
}
return retval
}

Writing a nested iterator of depth d

How to realize a nested iterator that takes a depth argument. A simple iterator would be when depth = 1. it is a simple iterator which runs like a simple for loop.
func Iter () chan int {
ch := make(chan int);
go func () {
for i := 1; i < 60; i++ {
ch <- i
}
close(ch)
} ();
return ch
}
Output is 1,2,3...59
For depth = 2 Output would be "1,1" "1,2" ... "1,59" "2,1" ... "59,59"
For depth = 3 Output would be "1,1,1" ... "59,59,59"
I want to avoid a nested for loop. What is the solution here ?
I don't know if it is possible to avoid nested loops, but one solution is to use a pipeline of channels. For example:
const ITER_N = 60
// ----------------
func _goFunc1(out chan string) {
for i := 1; i < ITER_N; i++ {
out <- fmt.Sprintf("%d", i)
}
close(out)
}
func _goFuncN(in chan string, out chan string) {
for j := range in {
for i := 1; i < ITER_N; i++ {
out <- fmt.Sprintf("%s,%d", j, i)
}
}
close(out)
}
// ----------------
// create the pipeline
func IterDepth(d int) chan string {
c1 := make(chan string)
go _goFunc1(c1)
var c2 chan string
for ; d > 1; d-- {
c2 = make(chan string)
go _goFuncN(c1, c2)
c1 = c2
}
return c1
}
You can test it with:
func main() {
c := IterDepth(2)
for i := range c {
fmt.Println(i)
}
}
I usually implement iterators using closures. Multiple dimensions don't make the problem much harder. Here's one example of how to do this:
package main
import "fmt"
func iter(min, max, depth int) func() ([]int, bool) {
s := make([]int, depth)
for i := range s {
s[i] = min
}
s[0] = min - 1
return func() ([]int, bool) {
s[0]++
for i := 0; i < depth-1; i++ {
if s[i] >= max {
s[i] = min
s[i+1]++
}
}
if s[depth-1] >= max {
return nil, false
}
return s, true
}
}
func main() {
// Three dimensions, ranging between [1,4)
i := iter(1, 4, 3)
for s, ok := i(); ok; s, ok = i() {
fmt.Println(s)
}
}
Try it out on the Playground.
It'd be a simple change for example to give arguments as a single int slice instead, so that you could have per-dimension limits, if such a thing were necessary.

Resources