6

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)
}
  • `tmp/sandbox471444382/main.go:10: syntax error: unexpected { at end of statement` – user2357112 Mar 11 '17 at 00:52
  • What makes you think slices have a `shift` method? – user2357112 Mar 11 '17 at 00:52
  • 1
    https://github.com/golang/go/wiki/SliceTricks mentions a subheading called Shift –  Mar 11 '17 at 00:53
  • 1
    That's not a method name. Also, Go doesn't have a `while` loop, either; [`for` is Go's `while`](https://tour.golang.org/flowcontrol/3). – user2357112 Mar 11 '17 at 00:56
  • ok, sorry I'm new to this language, what'd be the strategy in this case, to remove one element from the beginning, each iteration and print it –  Mar 11 '17 at 00:57
  • Why remove elements? Just loop over the slice with [`range`](https://gobyexample.com/range). – user2357112 Mar 11 '17 at 00:59
  • removing is essential, as slices get appended later again, and then they are iterated while remove, also in my code the slices are holding funcs, the question is a narrow down example using ints –  Mar 11 '17 at 01:00
  • i see, can you please put it together with the range, also appreciate with a bit of explanation on what is x and a in `x, a := a[0], a[1:]` –  Mar 11 '17 at 01:06
  • In the slice example on the wiki, `a` is supposed to be the slice, and `x` is the element you're shifting. The wiki example has a bug; by assigning to `a` with `:=`, it's actually creating a new `a` variable instead of assigning to the old one, which is unlikely to be the correct behavior. – user2357112 Mar 11 '17 at 01:14
  • yes, that's correct, I noticed that and just earlier replaced it with the `=` sign instead of `:=`, is it possible to do what I'm looking for in go? I'm also concerned about removing elements while iterating using range here, certain languages like C# and java don't allow that and not sure how go works in this case, that's why I had the example in while construct but we don't have while in here :( –  Mar 11 '17 at 01:16
  • seems like a hard problem to solve, not too many examples around... still researching –  Mar 11 '17 at 01:27

2 Answers2

4

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)
}
peterSO
  • 158,998
  • 31
  • 281
  • 276
  • Thanks Peter... didn't know for could be used like this, very similar to while loop –  Mar 11 '17 at 03:29
2

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:]
Roshambo
  • 2,692
  • 1
  • 27
  • 24
  • 1
    both `meow` and `purr` are to `cat` as `scnurr` is to .....???? If I ever came home to my cat uttering a `schnurr`, I'm really not sure how I'd react. Because, quite suddenly, I'd then be aware that some **creature-formerly-known-as-cat** (possibly unknown to science, folklore, existential dimension, etc.) has been snuggling on my lap for years. From an ethical standpoint, you should really add a disclaimer `> CAUTION: READER DISCRETION ADVISED`. – ardnew Jul 22 '21 at 07:17
  • `schnurr` is German for `purr`. coincidentally (or perhaps not) `schnurrbart` is German for mustache. – Roshambo Jul 23 '21 at 13:32
  • 1
    ^ the things I learn on stackoverflow :D – Julius Žaromskis Feb 25 '22 at 13:08