How to move elements from one slice to another - go

package main
import (
"fmt"
)
func main() {
arr0 := []int{
1,2,3,4,5,
}
arr1 := []int{}
fmt.Println(arr0)
fmt.Println(arr1)
fmt.Println("transferring...")
transfer(&arr0, &arr1)
fmt.Println(arr0)
fmt.Println(arr1)
}
func transfer(arr0 *[]int, arr1 *[]int) {
tmp := make([]int, 0)
for i:=0;i<len(*arr0);i++ {
tmp = append(tmp, (*arr0)[i])
}
arr1 = &tmp
s := make([]int, 0)
arr0 = &s
}
For function of transfer, I intented to transfer elements of slice arr0 to slice arr1 and empty slice arr0
But it is not successful
Here is my output
[1 2 3 4 5]
[]
transferring...
[1 2 3 4 5]
[]
After transferring, I need the result below.
[]
[1 2 3 4 5]
But actually, arr0, and arr1 in the main function remain as it was!
can someone tell me why this is not ok?
I thought in the memory, it should be like this
after running transfer function

#jacobsa has given an excellent answer.
Just keep that in mind. You can achieve the same effect but with better performance. Golang offers an excellent opportunity for this.
package main
import (
"fmt"
)
func main() {
arr0 := []int{
1, 2, 3, 4, 5,
}
arr1 := []int{}
fmt.Println(arr0)
fmt.Println(arr1)
fmt.Println("transferring...")
transfer(&arr0, &arr1)
fmt.Println(arr0)
fmt.Println(arr1)
}
func transfer(arr0 *[]int, arr1 *[]int) {
*arr0, *arr1 = *arr1, *arr0
}

These two lines:
arr1 = &tmp
arr0 = &s
change the local variables arr1 and arr0 within the function. Those variables happen to be pointers, but they are just copies of the input pointers provided by main—they are not references to the input pointers.
If you changed the things the arr1 and arr0 pointers point to, rather than the pointers themselves, then you would see a change to the values provided by main:
*arr1 = tmp
*arr0 = s

Related

Go subslice pointer reference

The result of s is [1, 2, 3], I thought that slices hold a reference to the underlying array. Isn't that the case?
package main
import (
"fmt"
)
func main() {
s := []int{1, 2, 3}
ss := s[1:]
ss = append(ss, 4)
for _, v := range ss {
v += 10
}
for i := range ss {
ss[i] += 10
}
fmt.Println(s)
}
I thought that slices hold a reference to the underlying array. Isn't that the case?
Yes it is. But you created an array with length 3 with this statement:
s := []int{1, 2, 3}
When you appended an element to ss, that required an allocation of a new, longer array. So you lost the link between ss and s with this statement:
ss = append(ss, 4)
You can verify that by running this example:
package main
import (
"fmt"
)
func main() {
s := []int{1, 2, 3}
ss := s[1:]
ss[0] += 5
ss = append(ss, 4)
ss[0] += 100
fmt.Println(s)
}
Which prints [1 7 3].
If you change your initialization of s to have a length greater than three, then no new array allocation will be required, and the link between s and ss will be maintained:
package main
import (
"fmt"
)
func main() {
s := make([]int, 3, 4)
s[0], s[1], s[2] = 1, 2, 3
ss := s[1:]
ss[0] += 5
ss = append(ss, 4)
ss[0] += 100
fmt.Println(s)
}
Output: [1 107 3]
The answer that theorizes that the problem is a range copy of the slice is incorrect, which can be shown with this example:
package main
import (
"fmt"
)
func main() {
s := make([]int, 3, 4)
s[0], s[1], s[2] = 1, 2, 3
ss := s[1:]
ss = append(ss, 4)
for i := range ss {
ss[i] += 10
}
fmt.Println(s)
}
Output: [1 12 13]
It seems like you've created a copy of slice s, and you've made changes to slice copy ss thinking that the changes would also be passed to the slice that the copy was made from.
The first for loop is also walking through the elements of slice ss, but is not actually doing anything with them, because range also creates a copy when providing you element values, so it doesn't actually do anything!
It does seem like you're trying to do the following:
Append the value 4 to slice s
Take each value from index 1 of slice to the end of the slice, and add 10
If that's the case, this should help you accomplish that:
package main
import (
"fmt"
)
func main() {
s := []int{1, 2, 3}
s = append(s, 4)
for i := range s {
if i == 0 {
continue
}
s[i] += 10
}
fmt.Println(s)
}
You can see this on the Go playground: Link

Change golang slice in another function

I have a slice, if i remove one element from it directly in a main function the length of slice would be cut by one. But do the remove in another function and called it in main, the length of the slice is still keep origin. Who can explain it for me? Thanks!
package main
import "fmt"
func main() {
a := []int{1, 2, 3, 4}
i := 0
//copy(a[i:], a[i+1:])
//a[len(a)-1] = 0
//a = a[:len(a)-1]
//fmt.Println(a) //outputs: [2 3 4], this is correct
f(a, i)
fmt.Println(a) //outputs: [2 3 4 0], this is wrong!
}
func f(a []int, i int) {
copy(a[i:], a[i+1:])
a[len(a)-1] = 0
a = a[:len(a)-1]
fmt.Println(a) //outputs: [2 3 4], here still correct
}
Go Playground Link
The slice is passed by value, so changing it in your function f won't change it in function main. You can pass by pointer, like this:
package main
import "fmt"
func main() {
a := []int{1, 2, 3, 4}
i := 0
f(&a, i)
fmt.Println(a) //outputs: [2 3 4], correct
}
func f(a *[]int, i int) {
b := *a
copy(b[i:], b[i+1:])
// The following line seems pointless, but ok...
b[len(b)-1] = 0
b = b[:len(b)-1]
fmt.Println(b) //outputs: [2 3 4], here still correct
*a = b
}
Go Playground
As suggested by #zerkms in the comments, you could also return the new slice, avoiding the use of pointers:
package main
import "fmt"
func main() {
a := []int{1, 2, 3, 4}
i := 0
a = f(a, i)
fmt.Println(a)
}
func f(a []int, i int) []int {
copy(a[i:], a[i+1:])
// The following line seems pointless, but ok...
a[len(a)-1] = 0
a = a[:len(a)-1]
fmt.Println(a) //outputs: [2 3 4], here still correct
return a
}
Not providing new solution, just trying to explain why your program is behaving the way you asked:
Let us try to understand first how the built in function ‘copy’ works

Ref: [https://golang.org/pkg/builtin/#copy]
func copy(dst, src []Type) int
The copy built-in function copies elements from a source slice into a destination slice. (As a special case, it also will copy bytes from a string to a slice of bytes.) The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum of len(src) and len(dst).
Two things:
1. 
First comment the line : //a[len(a)-1] = 0
Second: As you are using the same array i.e as source and destination you are getting [2,3,4,4] as output as the destination array is {1,2,3,4} which got overwritten to {2,3,4,4(which is already present)}

you can try with different array’s to make it more clear to you

Truncate slice in place

Given a slice (not a pointer to a slice!) is there any way to truncate it in place?
The naive implementation doesn't work, because of scope:
package main
import (
"fmt"
)
func truncate(s []int, to int) []int{
s = s[:to] # <- has no effect outside this function
return s
}
func main() {
s := []int{0, 1, 2, 3, 4}
s1 := truncate(s, 3)
fmt.Printf("%v\n", s1)
fmt.Printf("%v\n", s)
}
prints
[0 1 2]
[0 1 2 3 4] # <- can we get [0 1 2] here?
Is there any way to modify the length or capacity of an existing slice, or are they immutable?
ETA: I thought this was obvious enough, but apparently not: when I ask whether it's possible to do this in place, I mean without reassigning s.
This is the way to go:
package main
import "fmt"
func main() {
s := []int{0, 1, 2, 3, 4}
s = truncate(s, 3)
fmt.Println(s) // [0 1 2]
}
func truncate(s []int, to int) []int {
return s[:to]
}
Slice is like a window to an underlying array.
The other way using pointer to the slice:
package main
import "fmt"
func main() {
s := []int{0, 1, 2, 3, 4}
truncate(&s, 3)
fmt.Println(s) // [0 1 2]
}
func truncate(s *[]int, to int) {
*s = (*s)[:to]
}
This can't be done, because slices are passed by value.
Note that as of April 2013, the Go language specification no longer refers to slices, maps, and channels as "reference types". (The behavior didn't change, just the language used to describe it.)
It can't be done with arrays either, because an array's length is part of its type.

Flipping a slice with a for loop logic error

So I am trying to write a method that takes two slices, flips both of them and then gives them to each other.
Ex.
s1 = {1,2,3,4,5}
s2 = {6,7,8,9,10}
Should return:
s1 = {10,9,8,7,6}
s2 = {5,4,3,2,1}
Here is my code:
package main
import(
"fmt"
)
func main(){
f:= [5]int{1,2,3,4,5}
h:= [5]int{6,7,8,9,10}
var sliceF []int = f[0:5]
var sliceH []int = h[0:5]
fmt.Println(reverseReverse(sliceF,sliceH))
}
func reverseReverse(first []int, second []int) ([]int, []int){
//creating temp arrays to hold the traversed arrays before swapping.
var tempArr1 []int = first
var tempArr2 []int = second
//count is used for counting up the tempArrays in the correct order in the For loops
var count int= 0
//goes through the first array and sets the values starting from the end equal to the temp array
//which increases normally from left to right.
for i :=len(first)-1; i>=0;i--{
tempArr1[count] = first[i]
fmt.Println(i)
count++
}
count =0
//same as first for loop just on the second array
for i :=len(second)-1; i>=0;i--{
tempArr2[count] = second[i]
count++
}
//trying to replace the values of the param arrays to be equal to the temp arrays
first=tempArr2
second = tempArr1
//returning the arrays
return first,second
}
When run here is the output:
4
3
2
1
0
[10 9 8 9 10]
[5 4 3 4 5]
*Not I included a print statement in the for loop to check if the index is decreasing properly.
I understand there are better ways to do this but for proof of concept I want to use a for loop.
Any help appreciated. I am new to go and tend to have java habits so I assume somehow my problem is related to that.
This can be done much simpler by realizing there's no need to actually swap the individual elements. Instead, reverse each array and swap their order. Much simpler!
func reverseReverse( a, b []int ) ([]int, []int) {
return reverse(b), reverse(a)
}
func reverse( a []int ) []int {
end := len(a) - 1
// Allocate a new array slice of the same length to copy to.
ret := make( []int, len(a) )
// Copy each element of a into ret, reversed.
for i := range a {
ret[end-i] = a[i]
}
return ret
}
With that revelation, there's little need for the very specialized reverseReverse function. Swap the order yourself.
fmt.Println(reverse(sliceH), reverse(sliceF))
Note that if you just want to take a slice of an array, it's sufficient to write sliceH []int := h[:] without specifying the start and end. The start is assumed to be 0 and the end is the end. Also note there's no need to declare the type, := takes care of that for you.
Even better, you can declare and initialize them directly.
sliceF:= []int{1,2,3,4,5}
sliceH:= []int{6,7,8,9,10}
Short answer:
tempArr1[count] = first[i]
This line is logically identical to:
first[count] = first[i]
Detailed answer:
x := [5]int{} and x := []int{} are in fact two very different assignments. In the first case x is actually a static array. In the second case x is a slice which is in fact a data structure which has a length, capacity and a pointer to the underlying array. Therefore, var tempArr1 []int = first means copy the pointer to the underlying array of first into the tempArr1, so any modification to first[i] will be reflected in tempArr1 and vice versa
For example,
package main
import "fmt"
func reverse(s []int) []int {
for i := 0; i < len(s)/2; i++ {
s[i], s[len(s)-1-i] = s[len(s)-1-i], s[i]
}
return s
}
func main() {
s1, s2 := []int{1, 2, 3, 4, 5}, []int{6, 7, 8, 9, 10}
fmt.Println(s1, s2)
s1, s2 = reverse(s2), reverse(s1)
fmt.Println(s1, s2)
}
Output:
[1 2 3 4 5] [6 7 8 9 10]
[10 9 8 7 6] [5 4 3 2 1]

Why the function append in Go work with reference when pass a slice?

In the next code I'm trying to add an element of a slice of slices, but as Go works with reference, how can I use this by using the b slice by value?
package main
import (
"fmt"
)
func main() {
a := []int{1}
arr := [][]int{a}
b := []int{2}
arr = append(arr, b)
fmt.Println(arr)
b[0] = 3
arr = append(arr, b)
fmt.Println(arr)
}
I expected that the last Println was [[1] [2] [3]], but it's [[1] [3] [3]].
There is no way to insert a slice "by value"; you need to make a copy of the slice before inserting it:
package main
import (
"fmt"
)
func copy_ints(c []int) []int {
s := make([]int, len(c))
copy(s, c)
return s
}
func main() {
a := []int{1}
arr := [][]int{copy_ints(a)}
b := []int{2}
arr = append(arr, copy_ints(b))
fmt.Println(arr)
b[0] = 3
arr = append(arr, copy_ints(b))
fmt.Println(arr)
}
https://play.golang.org/p/Tds5FGj3nf

Resources