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.
Related
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
This question already has answers here:
How to find out element position in slice?
(10 answers)
Closed 2 years ago.
I am trying to find out the equivalent of indexof to get the position of specific element in array golang the purpose for integers in array.
package main
import (
"fmt"
)
func main() {
fmt.Println("what")
arr := []int{1, 2, 3, 4, 2, 2, 3, 5, 4, 4, 1, 6}
i := IndexOf(2, arr)
}
Write a function. Here's an example assuming that IndexOf returns the first index of the number or -1 if none is found.
// IndexOf returns the first index of needle in haystack
// or -1 if needle is not in haystack.
func IndexOf(haystack []int, needle int) int {
for i, v := range haystack {
if v == needle {
return i
}
}
return -1
}
Run this code on the Go Programming Language Playground.
There is no common library function to do this for you in go.
However if you are using a byte slice, you can use IndexByte(b []byte, c byte) int.
Or you can write a quick function which does this for you:
func indexOf(arr []int, val int) int {
for pos, v := range arr {
if v == val {
return pos
}
}
return -1
}
package main
import "fmt"
func IndexOf(arr []int, candidate int) int {
for index, c := range arr {
if c == candidate {
return index
}
}
return -1
}
func main() {
fmt.Println("what")
arr := []int{1, 2, 3, 4, 2, 2, 3, 5, 4, 4, 1, 6}
i := IndexOf(arr, 2)
fmt.Println(i)
}
Add a method IndexOf to search, this is a linear search method.
Ref: https://play.golang.org/p/Hp6Dg--XoIV
There is no equivalent for IndexOf in Go. You need to implement one your self. But if you have have sorted array of Ints, you can use sort.SearchInts as shown below.
package main
import (
"fmt"
"sort"
)
func main() {
fmt.Println(sort.SearchInts([]int{2,3,4,5,9,10,11}, 5))
}
Also from the godoc:
SearchInts searches for x in a sorted slice of ints and returns the index as specified by Search. The return value is the index to insert x if x is not present (it could be len(a)). The slice must be sorted in ascending order.
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
I'm learning GO and I have a theoretical problem.
How do I use a copy of slice rather than a reference to it?
package main
import "fmt"
func main() {
// slice containing 3 items
slice1 := []int{1, 2, 3}
// make an empty slice
slice2 := make([]int, 2, 5)
// create slice3 by appending int 4 to slice2
slice3 := append(slice2, 4)
// print [0 0 4]
fmt.Println(slice3)
// copy elements of slice1 onto slice2
copy(slice2, slice1)
// print [1 2 3] [1 2] [1 2 4]; how to make sure slice3 is using a copy [0 0 4]?
fmt.Println(slice1, slice2, slice3)
}
problem playground link
I have came up with a potential solution, but it is pointless as it relies on slice3 being created empty and slice2 being copied via copy() onto slice3. Is there no shortcut?
package main
import "fmt"
func main() {
// slice containing 3 items
slice1 := []int{1, 2, 3}
// make an empty slice
slice2 := make([]int, 2, 5)
// create slice3, copy slice2 and append int 4 to slice3
slice3 := make([]int, 2)
copy(slice3, slice2)
slice3 = append(slice3, 4)
// print [0 0 4]
fmt.Println(slice3)
// copy elements of slice1 onto slice2
copy(slice2, slice1)
// print [1 2 3] [1 2] [0 0 4];
fmt.Println(slice1, slice2, slice3)
}
solution playground link
EDIT:
I've read that there is a peculiar behaviour that in this naive example would work as a solution (see below). However, in any other case it would not work.
Basically, if the empty slice is created without the size of an underlying array being specified, GO's append function provides a copy of that array, otherwise, if there is room to grow, append will return a slice that references the original array.
Note: the only change is slice2 := make([]int, 2, 5) into slice2 := make([]int, 2)
package main
import "fmt"
func main() {
// slice containing 3 items
slice1 := []int{1, 2, 3}
// make an empty slice
slice2 := make([]int, 2)
// create slice3 by appending int 4 to slice2
slice3 := append(slice2, 4)
// print [0 0 4]
fmt.Println(slice3)
// copy elements of slice1 onto slice2
copy(slice2, slice1)
// print [1 2 3] [1 2] [1 2 4]; how to make sure slice3 is using a copy [0 0 4]?
fmt.Println(slice1, slice2, slice3)
}
playground with a wanted behaviour
So the question becomes: Is it possible to replicate the behaviour of the above, when the slice we are appending to points to an array with specified size and room to grow?
EDIT 2:
I think there is some confusion as to what I want to achieve.
How to get the result of the second call while passing a slice in the format used in the first call?
package main
import "fmt"
func main() {
fmt.Println("s3 references an array of s1")
worker(make([]int, 2, 5))
fmt.Println("\ns3 copies an array of s1")
worker(make([]int, 2))
}
func worker(s1 []int) {
s2 := []int{1, 2, 3}
fmt.Println(s1)
s3 := append(s1, 4)
fmt.Println(s3)
copy(s1, s2)
fmt.Println(s3)
}
playground
A few people commented that I was not clear enough last night. So I would like to clarify and provide an answer that I arrived at with the help of #CoreyOgburn and #JimB
I was learning about slices in GO and I found an inconsistency, that led me to believe I'm doing something wrong. While hardly a real life example I found the following a good example of the copy and append functionality.
package main
import "fmt"
func main() {
fmt.Println("s3 references an array of s1")
// we pass a slice of length 2 and capacity 5
worker(make([]int, 2, 5))
fmt.Println("\ns3 copies an array of s1")
// we pass a slice of lenght 2 and capacity 2
worker(make([]int, 2))
}
func worker(s1 []int) {
// create new slice for future use
s2 := []int{1, 2, 3}
fmt.Println(s1)
// create a new slice by appending a value to a slice passed into this function
s3 := append(s1, 4)
// s3 holds whatever was passed into this function + int 4, that we just appended
fmt.Println(s3)
// copy contents of s2 onto s1
copy(s1, s2)
// if s1 had spare capacity when it was passed i.e. make([]int, 2, 5) s3 will be referencing the same array as s1, hence s3 will now hold the same values as s1
// if s1 capacity was the same as its length i.e. make([]int, 2) s3 will be referencing a new array after append(), hence copy has no effect on the values of s3
fmt.Println(s3)
}
#JimB posted a comment with a link to a blog post explaining how slices work, which is a great read if you are learning the language.
What is most important in the section A possible "gotcha" there is an explanation of a 'fix' to a real life scenario, that can be extrapolated as a fix the inconsistency in my example. (create a copy of a passed slice and use that instead)
Playground
I am trying to reverse-sort a slice of integers in Go.
example := []int{1,25,3,5,4}
sort.Ints(example) // this will give me a slice sorted from 1 to the highest number
How do I sort it so that it goes from highest to lowest? so [25 5 4 3 1]
I have tried this
sort.Sort(sort.Reverse(sort.Ints(keys)))
Source: http://golang.org/pkg/sort/#Reverse
However, I am getting the error below
# command-line-arguments
./Roman_Numerals.go:31: sort.Ints(keys) used as value
sort.Ints is a convenient function to sort a couple of ints. Generally you need to implement the sort.Interface interface if you want to sort something and sort.Reverse just returns a different implementation of that interface that redefines the Less method.
Luckily the sort package contains a predefined type called IntSlice that implements sort.Interface:
keys := []int{3, 2, 8, 1}
sort.Sort(sort.Reverse(sort.IntSlice(keys)))
fmt.Println(keys)
package main
import (
"fmt"
"sort"
)
func main() {
example := []int{1, 25, 3, 5, 4}
sort.Sort(sort.Reverse(sort.IntSlice(example)))
fmt.Println(example)
}
Playground
Output:
[25 5 4 3 1]
Instead of using two function calls and a cast, you can do it with just sort.Slice:
package main
import (
"fmt"
"sort"
)
func main() {
example := []int{1,25,3,5,4}
sort.Slice(example, func(a, b int) bool {
return example[b] < example[a]
})
fmt.Println(example)
}
https://golang.org/pkg/sort#Slice