Fallen
Fallen

Reputation: 4565

Slicing a slice

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.

Upvotes: 5

Views: 11684

Answers (5)

icza
icza

Reputation: 417512

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]

Upvotes: 9

Vadim Shender
Vadim Shender

Reputation: 6723

General (as you ask in a comment) function for arbitrary number of elements:

func strip(s []int, n int) []int {
    if len(s) < n {
        n = len(s)
    }
    return s[:n]
}

...
foo := strip(bar, 2)

Go Playground example

Upvotes: 0

IamNaN
IamNaN

Reputation: 6864

bar := []int{}
n := len(bar)
if n > 2 {
    n = 2
}
foo := bar[:n]
fmt.Printf("%v", foo)

Works with len(bar) = 0, 1, 2, n.. Playground sample

Upvotes: 0

Ainar-G
Ainar-G

Reputation: 36189

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)]
}

Upvotes: 4

ANisus
ANisus

Reputation: 77945

Go does not have a math.MinInt. But implementing one is as simple as:

func Min(x, y int) int {
    if x < y {
        return x
    }
    return y
}

...

foo := bar[:Min(len(bar), 2)]

Upvotes: 1

Related Questions