Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Slicing a slice

Tags:

slice

go

Problem description: I've a slice bar. I want to create another slice foo with the first two elements of bar if there're at least 2 elements in bar. Or with the first element of bar if bar has at least one element.

The idea I had:

// bar := []int{1, 2, 3...
foo := bar[:(int)(math.Min(float64(len(bar)), 2))]

EDIT: Here's another way I tried,

x := 2
if len(bar) < 2 {
    x = len(bar)
}
foo := bar[:x]

Is it possible to improve the code? At least, casting twice to achieve something so simple doesn't look good to me.

like image 581
Fallen Avatar asked Dec 19 '22 05:12

Fallen


2 Answers

If the length of your slice is greater than 2, you can reslice it. If not, no need to reslice just use the slice itself in assignment which will automatically satisfy your needs: result will have up to a maximum of 2 elements.

You can even "spare" the else branch of the if:

foo := bar
if len(foo) > 2 {
    foo = foo[:2]
}

Note:

Slices are reference types. So even though you used bar to initialize foo, if you modify the foo variable afterwards (not the elements of the slice), that does not affect bar (the reference value is copied when assigned):

bar := []int{0, 1, 2, 3}
foo := bar
if len(foo) > 2 {
    foo = foo[:2]
}
fmt.Println(foo) // Here foo is [0, 1] as expected

foo = foo[:1]    // Reslicing foo
fmt.Println(bar) // Bar is unaffected, bar = [0 1 2 3]

Output (try it on the Go Playground):

[0 1]
[0 1 2 3]
like image 78
icza Avatar answered Jan 18 '23 10:01

icza


Just use an if. It's much more readable and performant, since there is no conversion between int and float64.

var foo []int
if len(bar) > 1 {
    foo = bar[:2]
} else {
    foo = bar[:len(bar)]
}
like image 30
Ainar-G Avatar answered Jan 18 '23 09:01

Ainar-G