If I have two pointers to slices s1, s2, which initially point to the same slice, is it possible to append to one of the slices and have the other slice also point to the updated slice? This seems to be a problem because, appending to slices might make a new slice with the entries copied over if the capacity is insufficient.
The following is a slightly complicated version on the Go Playground that is closer to my use case. Namely, I have nodes that have a pointer to a (global) queue which is implemented by a slice. When one node updates the global queue, I want that to be reflected in the slice that the other node points to.
https://play.golang.org/p/NG11HbLBrI
Add a indirect layer, i.e. a pointer, can help you work this out
https://play.golang.org/p/R7JILCbYTF
package main
import (
"fmt"
)
type queue *[]int
type node struct {
id int
list *queue
}
func (n *node) mutate(){
newSlice := append(**n.list, 1)
*n.list = &newSlice
}
func (n *node) get(idx int) int{
return (*(*[]int)(*n.list))[idx]
}
func main() {
/* Make empty queue */
s:=make([]int, 0)
q1:=queue(&s)
fmt.Println(q1)
/* Make new nodes */
n1 := new(node)
n1.id = 0
n1.list = &q1
fmt.Println(n1)
n2 := new(node)
n2.id = 1
n2.list = n1.list
fmt.Println(n2)
/* Mutate node in n1 */
n1.mutate()
fmt.Println(n1, n2) // n1.list != n2.list
fmt.Println(n1.list, n2.list)
fmt.Println(n1.get(0))
n2.mutate()
fmt.Println(n2.get(0))
}
Related
A go method on struct receives pointer reference, made some modifications and returning same pointer. The struct has nested reference of same struct: when append method being called with values some reason it was loosing previous values.
package main
import (
"fmt"
)
type Node struct{
next *Node
val int
}
func newNode(val int) (*Node){
n := Node{
val: val,
}
return &n
}
func (n *Node) append(val int) (*Node){
for n.next != nil {
n = n.next
}
n.next = newNode(val)
return n
}
func (n *Node)printList(){
for n != nil {
fmt.Printf("%d,", n.val)
n = n.next
}
fmt.Println()
}
func main() {
n := newNode(3)
n.printList()
n = n.append(4)
n.printList()
n = n.append(5)
n.printList()
n = n.append(6)
n.printList()
}
output:
3,
3,4,
4,5,
5,6,
I was expecting 3,4,5,6, - Probably something I totally missing something fundamentals here. appreciate if you have some inputs.
https://play.golang.org/p/-zDH98UNFLa
I was getting expected results when I modify append method not return anything.
append() returns the pointer of the next node. Therefore printList() only print the nodes starting from the next node. If you'd like to print the all nodes in the list, you should add a variable to store the pointer referenced to the starting node of this list.
func main() {
n := newNode(3)
head := n
head.printList()
n = n.append(4)
head.printList()
n = n.append(5)
head.printList()
n = n.append(6)
head.printList() // 3,4,5,6
}
This function:
func (n *Node) append(val int) (*Node){
for n.next != nil {
n = n.next
}
n.next = newNode(val)
return n
}
does not return its original argument in general. It returns the node that is next-to-last in the (assumed to be non-empty) list. Hence:
n = n.append(4)
adds a node holding 4 to the original node holding 3, then returns the original node holding 3, but:
n = n.append(5)
adds a node holding 5 to the original list, but then returns a pointer to the node holding 4. That's why you see 4,5, at this point. Subsequent calls keep repeating the last two elements for the same reason.
You could modify your append function to save the original return value and return that:
func (n *Node) append(val int) *Node {
// find current tail
t := n
for t.next != nil {
t = t.next
}
t.next = newNode(val)
return n
}
but overall this is still not a great strategy: this append does not work when given a nil-valued n, for instance. Consider constructing a list type that does handle such cases. Alternatively, as in Hsaio's answer, you can have the caller hang on to the head node directly. If you do that you could have the append function return the tail pointer:
func (n *Node) append(val int) *Node {
n.next = newNode(val)
return n.next
}
and then use it like this:
head := newNode(3)
t := append(head, 4)
t = append(t, 5)
t = append(t, 6)
head.printList()
(There's already a List implementation in the standard Go packages, container/list, that does this stuff nicely for you. Instead of pointing directly to each element in your list, you create an overall list-container instance, which allows you to insert-at-front, insert-at-back, remove-from-anywhere, and so on. It's a little awkward in that it uses interface{} for the data, so it requires a type-assertion to get each node's value.)
The variable n in main function is overrided by n in append function.
I'm trying to implement a very simple queue in Go using slices. This is the code that I have to enqueue five values and then discard the first two values:
package main
import (
"fmt"
)
var (
localQ []int
)
func main() {
fmt.Printf("%v %v\n", localQ, len(localQ))
for i := 0; i< 5; i++ {
localQ = enqueue(localQ, i)
fmt.Printf("%v %v\n", localQ, len(localQ))
}
localQ = dequeue(localQ, 2)
fmt.Printf("%v %v\n", localQ, len(localQ))
}
func enqueue(q []int, n int) ([]int) {
q = append(q, n)
return q
}
func dequeue(q []int, s int) ([]int) {
r := q[s:]
q = nil
return r
}
Two questions regarding the dequeue func:
1- I'm trying to ensure that the popped items are discarded and garbage collected. Does this function result them to be garbage collected?
2- What are the time and space complexities of r := q[s:]? I know there is an array under each slice. Are the array values being copied? Or is it just a pointer being copied?
Does this function result them to be garbage collected?
If the application enqueues a sufficient number of elements to cause the slice backing array to be reallocated, then the previous backing array (and its elements) will be eligible for collection.
What are the time and space complexities of r := q[s:]?
This is an O(1) operation. The operation does not allocate memory on the heap.
(I'm new to Go.)
I am working on this leetcode problem: https://leetcode.com/problems/pascals-triangle/
package main
import "fmt"
func main() {
arrRes := [][]int{}
gen(5, arrRes)
fmt.Println(arrRes)
}
func gen(numRows int, arrRes [][]int) {
build(numRows, 0, arrRes)
}
func build(n int, level int, arrRes [][]int) {
if(n == level) {
return
}
arr := []int{}
if level == 0 {
arr = append(arr, 1)
} else if level == 1 {
arr = append(arr, 1, 1)
} else {
// get it out
tmp := arrRes[level-1]
arr = comb(tmp)
}
arrRes = append(arrRes, arr)
build(n, level+1, arrRes)
}
func comb(arr []int) []int{
// arr type init
tmpArr := []int{1}
for i:=1; i<len(arr); i++ {
sum := arr[i-1] + arr[i]
tmpArr = append(tmpArr, sum)
}
// go use val, not ref
tmpArr = append(tmpArr, 1)
return tmpArr;
}
I want to define an accumulated variable arrRes := [][]int{} and keep passing into the recursive function. I think Go is pass-by-value instead of pass-by-reference. Is there a way to keep this pattern?
I've got two alternative methods:
passing a global var.
pass a 2D array into the func then return the new 2D array.
https://github.com/kenpeter/go_tri/blob/master/tri_global.go
https://github.com/kenpeter/go_tri/blob/master/tri.go
A slice is (basically) three things: a length, a capacity, and a pointer to an underlying array. Everything in Go is pass-by-value, so when you pass a slice to a function you are passing its current length, current capacity, and the memory address of the pointer. Changes made to length and capacity inside the function are made to a copy, and will not affect the length and capacity of the slice that was passed as an argument in the function call.
Printing a slice doesn't print its underlying array, it prints the part of the underlying array that is visible in the slice (which could be none of it if len = 0), based on (1) the pointer to the first element in the underlying array that's supposed to be visible to the slice; and (2) the length in the slice variable.
If you are modifying the length or capacity of a slice inside a function and you want those changes to be visible outside the function, you can either return the slice to update the context outside the function, like append does:
numbers := append(numbers, 27)
Or you can pass in a pointer to a slice:
func ChangeNumbersLenOrCap(numbers *[]int) {
// make your changes, no return value required
}
For your program, it looks like you could get away with a pointer to a slice of int slices:
var arrRes *[][]int
...because you're not modifying the int slice across another function boundary. Some programs would need a pointer to a slice of pointers to int slices:
var arrRes *[]*[]int
Here are some simple edits to get you started:
arrRes := [][]int{}
gen(5, &arrRes)
fmt.Println(arrRes)
}
func gen(numRows int, arrRes *[][]int) {
// ...
func build(n int, level int, arrRes *[][]int) {
// ...
tmp := *arrRes[level-1]
// ...
*arrRes = append(*arrRes, arr)
build(n, level+1, arrRes)
I need to create a 2 dimensional string array as shown below -
matrix = [['cat,'cat','cat'],['dog','dog']]
Code:-
package main
import (
"fmt"
)
func main() {
{ // using append
var matrix [][]string
matrix[0] = append(matrix[0],'cat')
fmt.Println(matrix)
}
}
Error:-
panic: runtime error: index out of range
goroutine 1 [running]:
main.main()
/tmp/sandbox863026592/main.go:11 +0x20
You have a slice of slices, and the outer slice is nil until it's initialized:
matrix := make([][]string, 1)
matrix[0] = append(matrix[0],'cat')
fmt.Println(matrix)
Or:
var matrix [][]string
matrix = append(matrix, []string{"cat"})
fmt.Println(matrix)
Or:
var matrix [][]string
var row []string
row = append(row, "cat")
matrix = append(matrix, row)
The problem with doing two-dimensional arrays with Go is that you have to initialise each part individually, e.g., if you have a [][]bool, you gotta allocate []([]bool) first, and then allocate the individual []bool afterwards; this is the same logic regardless of whether you're using make() or append() to perform the allocations.
In your example, the matrix[0] doesn't exist yet after a mere var matrix [][]string, hence you're getting the index out of range error.
For example, the code below would create another slice based on the size of an existing slice of a different type:
func solve(board [][]rune, …) {
x := len(board)
y := len(board[0])
visited := make([][]bool, x)
for i := range visited {
visited[i] = make([]bool, y)
}
…
If you simply want to initialise the slice based on a static array you have, you can do it directly like this, without even having to use append() or make():
package main
import (
"fmt"
)
func main() {
matrix := [][]string{{"cat", "cat", "cat"}, {"dog", "dog"}}
fmt.Println(matrix)
}
https://play.golang.org/p/iWgts-m7c4u
The code snippet below is the library implementation of the push methods for a priority queue. I am wondering why the line with the code a = a[0 : n+1] does not throw an out of bounds errors.
func (pq *PriorityQueue) Push(x interface{}) {
// Push and Pop use pointer receivers because they modify the slice's length,
// not just its contents.
// To simplify indexing expressions in these methods, we save a copy of the
// slice object. We could instead write (*pq)[i].
a := *pq
n := len(a)
a = a[0 : n+1]
item := x.(*Item)
item.index = n
a[n] = item
*pq = a
}
a slice is not an array; it is a view onto an existing array. The slice in question is backed by an array larger than itself. When you define a slice of an existing slice, you're actually slicing the underlying array, but the indexes referenced are relative to the source slice.
That's a mouthful. Let's prove this in the following way: we'll create a slice of zero length, but we'll force the underlying array to be larger. When creating a slice with make, the third parameter will set the size of the underlying array. The expression make([]int, 0, 2) will allocate an array of size 2, but it evaluates to a size-zero slice.
package main
import ("fmt")
func main() {
// create a zero-width slice over an initial array of size 2
a := make([]int, 0, 2)
fmt.Println(a)
// expand the slice. Since we're not beyond the size of the initial
// array, this isn't out of bounds.
a = a[0:len(a)+1]
a[0] = 1
fmt.Println(a)
fmt.Println(a[0:len(a)+1])
}
see here. You can use the cap keyword to reference the size of the array that backs a given slice.
The specific code that you asked about loops over cap(pq) in the calling context (container/heap/example_test.go line 90). If you modify the code at the call site and attempt to push another item into the queue, it will panic like you expect. I ... probably wouldn't suggest writing code like this. Although the code in the standard library executes, I would be very sour if I found that in my codebase. It's generally safer to use the append keyword.
Because it works in a specific example program. Here are the important parts from the original/full example source)
const nItem = 10
and
pq := make(PriorityQueue, 0, nItem)
and
for i := 0; i < cap(pq); i++ {
item := &Item{
value: values[i],
priority: priorities[i],
}
heap.Push(&pq, item)
}
Is it an example from container/heap? If yes, then it doesn't throws an exception because capacity is big enough (see how the Push method is used). If you change the example to Push more items then the capacity, then it'll throw.
It does in general; it doesn't in the container/heap example. Here's the general fix I already gave you some time ago.
func (pq *PriorityQueue) Push(x interface{}) {
a := *pq
n := len(a)
item := x.(*Item)
item.index = n
a = append(a, item)
*pq = a
}
Golang solution to Project Euler problem #81