slice shift like function in go lang - go

how array shift function works with slices?
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
for k, v := range s {
x, a := s[0], s[1:] // get and remove the 0 index element from slice
fmt.Println(a) // print 0 index element
}
}
I found an example from slice tricks but can't get it right.
https://github.com/golang/go/wiki/SliceTricks
x, a := a[0], a[1:]
Edit can you please explain why x is undefined here?
Building upon the answer and merging with SliceTricks
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
fmt.Println(len(s), s)
for len(s) > 0 {
x, s = s[0], s[1:] // undefined: x
fmt.Println(x) // undefined: x
}
fmt.Println(len(s), s)
}

For example,
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
fmt.Println(len(s), s)
for len(s) > 0 {
x := s[0] // get the 0 index element from slice
s = s[1:] // remove the 0 index element from slice
fmt.Println(x) // print 0 index element
}
fmt.Println(len(s), s)
}
Output:
6 [2 3 5 7 11 13]
2
3
5
7
11
13
0 []
References:
The Go Programming Language Specification: For statements
Addendum to answer edit to question:
Declare x,
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
fmt.Println(len(s), s)
for len(s) > 0 {
var x int
x, s = s[0], s[1:]
fmt.Println(x)
}
fmt.Println(len(s), s)
}
Output:
6 [2 3 5 7 11 13]
2
3
5
7
11
13
0 []
You can copy and paste my code for any slice type; it infers the type for x. It doesn't have to be changed if the type of s changes.
for len(s) > 0 {
x := s[0] // get the 0 index element from slice
s = s[1:] // remove the 0 index element from slice
fmt.Println(x) // print 0 index element
}
For your version, the type for x is explicit and must be changed if the type of s is changed.
for len(s) > 0 {
var x int
x, s = s[0], s[1:]
fmt.Println(x)
}

Just a quick explanation on how we implement shift-like functionality Go. It's actually a very manual process. Take this example:
catSounds := []string{"meow", "purr", "schnurr"}
firstValue := stuff[0] // meow
catSounds = catSounds[1:]
On the first line, we create our slice.
On the second line we get the first element of the slice.
On the third line, we re-assign the value of catSounds to everything currently in catSounds after the first element (catSounds[1:]).
So given all that, we can condense the second and third lines with a comma for brevity:
catSounds := []string{"meow", "purr", "schnurr"}
firstValue, catSounds := catSounds[0], catSounds[1:]

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

Does slice assignment in Go copy memory

Purpose: I have a big buffer, and I would like to have an array/slice of pointer pointing to different loc in the buffer.
What I am doing:
datPtrs := make([][]byte, n)
for i:=0; i<n; i++{
datPtrs[i] = bigBuf[i*m:(i+1)*m]
}
My Question:
Will this copy memory? My guess is not, but I cannot find anywhere to confirm this.
What is the best way/tool to find out whether there is memory copy or not?
Go slices are implemented as a struct:
src/runtime/slice.go:
type slice struct {
array unsafe.Pointer
len int
cap int
}
You are assigning/copying the slice struct, which does not copy the underlying array, only its pointer.
A simple illustration:
package main
import (
"fmt"
)
func main() {
buf := make([]byte, 8)
for i := range buf {
buf[i] = byte(i)
}
sub := buf[1:3]
fmt.Println(buf)
fmt.Println(sub)
for i := range sub {
sub[i] += 43
}
fmt.Println(buf)
fmt.Println(sub)
}
Playground: https://play.golang.org/p/4OzPwuNmUlY
Output:
[0 1 2 3 4 5 6 7]
[1 2]
[0 44 45 3 4 5 6 7]
[44 45]
See The Go Blog: Go Slices: usage and internals,
No
Slice is just a pointer to memory + len and cap
see: Why can not I duplicate a slice with `copy()` in Golang?
Like so:
package main
import (
"fmt"
)
func main() {
bigBuf := []byte{1, 2, 3, 4, 5}
datPtrs := make([][]byte, 2)
for i := 0; i < 2; i++ {
datPtrs[i] = bigBuf[i : i+1]
}
fmt.Println(bigBuf) // [1 2 3 4 5]
datPtrs[0][0] = 10
fmt.Println(bigBuf) // [10 2 3 4 5]
datPtrs[1][0] = 20
fmt.Println(bigBuf) // [10 20 3 4 5]
}

How to find an element intersect in other array

I have an array like:
a:= [1,2,3,4,5]
b:= [5,6,7,8,9]
How to know array b have contain element in array a without using foreach?
How to know array b have contain element in array a without using foreach?
You can't. And you should not try as this is pointless restriction.
If the arrays are sorted (as they appear to be in your question) there is an algorithm that works better than going through each element.
Pick the first element of a, call it x.
Binary search b for the first element equal or greater than x. If they are equal, you found an element that is contained in both arrays, if not, make that your new x. Now search a for x in the same way. Repeat until you run out of elements in one of the arrays.
This can be trivially extended to an arbitrary number of arrays (in fact, it's easier to write with an arbitrary number of arrays).
Here's a quick and dirty implementation:
package main
import (
"fmt"
"sort"
)
func inter(arrs ...[]int) []int {
res := []int{}
x := arrs[0][0]
i := 1
for {
off := sort.SearchInts(arrs[i], x)
if off == len(arrs[i]) {
// we emptied one slice, we're done.
break
}
if arrs[i][off] == x {
i++
if i == len(arrs) {
// x was in all the slices
res = append(res, x)
x++ // search for the next possible x.
i = 0
}
} else {
x = arrs[i][off]
i = 0 // This can be done a bit more optimally.
}
}
return res
}
func main() {
a := []int{1, 2, 3, 4, 5, 7}
b := []int{5, 6, 7, 8, 9}
fmt.Println(inter(a, b))
}
package main
import (
set "github.com/deckarep/golang-set"
)
func array_intersect(a, b []interface{}) []interface{} {
return set.NewSetFromSlice(a).Intersect(set.NewSetFromSlice(b)).ToSlice()
}
func main() {
a := []interface{}{1, 2, 3, 4, 5, 7}
b := []interface{}{5, 6, 7, 8, 9}
println(array_intersect(a, b))
}
package main
import (
"fmt"
"sort"
)
func array_intersect(a, b []int) []int {
ret := []int{}
lenA := len(a)
lenB := len(b)
if lenA == 0 || lenB == 0 {
return ret
}
sort.Ints(a)
sort.Ints(b)
var i, j int
for {
a = a[i:]
if i = sort.SearchInts(a, b[j]); i >= len(a) {
break
}
if a[i] == b[j] {
ret = append(ret, a[i])
}
if j++; j >= lenB {
break
}
}
return ret
}
func main() {
a := []int{5, 7, 1, 1, 2, 3, 4, 5, 7}
b := []int{1, 1, 5, 6, 7, 8, 9}
fmt.Printf("a=%v, b=%v", a, b)
fmt.Printf("%v\n", array_intersect(a, b))
fmt.Printf("a=%v, b=%v", a, b)
}

Golang remove elements when iterating over slice panics

I want delete some elements from a slice, and https://github.com/golang/go/wiki/SliceTricks advise this slice-manipulation:
a = append(a[:i], a[i+1:]...)
Then I coded below:
package main
import (
"fmt"
)
func main() {
slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
for i, value := range slice {
if value%3 == 0 { // remove 3, 6, 9
slice = append(slice[:i], slice[i+1:]...)
}
}
fmt.Printf("%v\n", slice)
}
with go run hello.go, it panics:
panic: runtime error: slice bounds out of range
goroutine 1 [running]:
panic(0x4ef680, 0xc082002040)
D:/Go/src/runtime/panic.go:464 +0x3f4
main.main()
E:/Code/go/test/slice.go:11 +0x395
exit status 2
How can I change this code to get right?
I tried below:
1st, with a goto statement:
func main() {
slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
Label:
for i, n := range slice {
if n%3 == 0 {
slice = append(slice[:i], slice[i+1:]...)
goto Label
}
}
fmt.Printf("%v\n", slice)
}
it works, but too much iteration
2nd, use another slice sharing same backing array:
func main() {
slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
dest := slice[:0]
for _, n := range slice {
if n%3 != 0 { // filter
dest = append(dest, n)
}
}
slice = dest
fmt.Printf("%v\n", slice)
}
but not sure if this one is better or not.
3rd, from Remove elements in slice, with len operator:
func main() {
slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
for i := 0; i < len(slice); i++ {
if slice[i]%3 == 0 {
slice = append(slice[:i], slice[i+1:]...)
i-- // should I decrease index here?
}
}
fmt.Printf("%v\n", slice)
}
which one should I take now?
with benchmark:
func BenchmarkRemoveSliceElementsBySlice(b *testing.B) {
for i := 0; i < b.N; i++ {
slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
dest := slice[:0]
for _, n := range slice {
if n%3 != 0 {
dest = append(dest, n)
}
}
}
}
func BenchmarkRemoveSliceElementByLen(b *testing.B) {
for i := 0; i < b.N; i++ {
slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
for i := 0; i < len(slice); i++ {
if slice[i]%3 == 0 {
slice = append(slice[:i], slice[i+1:]...)
}
}
}
}
$ go test -v -bench=".*"
testing: warning: no tests to run
PASS
BenchmarkRemoveSliceElementsBySlice-4 50000000 26.6 ns/op
BenchmarkRemoveSliceElementByLen-4 50000000 32.0 ns/op
it seems delete all elements in one loop is better
Iterate over the slice copying elements that you want to keep.
k := 0
for _, n := range slice {
if n%3 != 0 { // filter
slice[k] = n
k++
}
}
slice = slice[:k] // set slice len to remaining elements
The slice trick is useful in the case where a single element is deleted. If it's possible that more than one element will be deleted, then use the for loop above.
working playground example
while this is good answer for small slice:
package main
import "fmt"
func main() {
slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
k := 0
for _, n := range slice {
if n%3 != 0 { // filter
slice[k] = n
k++
}
}
slice = slice[:k]
fmt.Println(slice) //[1 2 4 5 7 8]
}
for minimizing memory write for first elements (for big slice), you may use this:
package main
import "fmt"
func main() {
slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
k := 0
for i, n := range slice {
if n%3 != 0 { // filter
if i != k {
slice[k] = n
}
k++
}
}
slice = slice[:k]
fmt.Println(slice) //[1 2 4 5 7 8]
}
and if you need new slice or preserving old slice:
package main
import "fmt"
func main() {
slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
s2 := make([]int, len(slice))
k := 0
for _, n := range slice {
if n%3 != 0 { // filter
s2[k] = n
k++
}
}
s2 = s2[:k]
fmt.Println(s2) //[1 2 4 5 7 8]
}

Why does range iterating with _ blank identifier produce different values

I'm learning Go and having a great time so far.
The following code outputs the sum as 45
package main
import "fmt"
func main(){
//declare a slice
numSlice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
var sum int = 0
for num := range numSlice {
sum += num
fmt.Println("num =", num)
}
fmt.Println("sum =", sum)
}
The following code, where I use _ the blank identifier to ignore the index in the for declaration outputs the sum as 55
//declare a slice
numSlice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
var sum int = 0
for _,num := range numSlice {
sum += num
fmt.Println("num =", num)
}
fmt.Println("sum =", sum)
This has got me slightly stumped. From my understanding the blank identifier is used to ignore the slice index . But it also seems to be shifting the index and thereby ignoring the last element in the slice.
Can you please explain what's happening here and possibly why. I'm assuming this is not a bug and is by design. Go is so well designed so what would the possible use cases be for this kind of behaviour?
Single parameter range uses indexes, not values. Because your indexes are also going up from 0 to 9 using range with a single param will add the indexes up from 0 to 9 and give you 45
package main
import "fmt"
func main(){
//declare a slice
numSlice := []int{0, 0, 0, 0}
var sum int = 0
for num := range numSlice {
sum += num
fmt.Println("num =", num)
}
fmt.Println("sum =", sum)
}
Output
num = 0
num = 1
num = 2
num = 3
sum = 6

Resources