切割一个切片

huangapple go评论84阅读模式
英文:

Slicing a slice

问题

问题描述:
我有一个切片 bar。如果 bar 中至少有两个元素,我想用 bar 的前两个元素创建另一个切片 foo。如果 bar 至少有一个元素,我想用 bar 的第一个元素创建 foo

我想到的方法是:

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

编辑:
这是我尝试的另一种方法:

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

有没有可能改进这段代码?至少,为了实现这么简单的功能而进行两次类型转换看起来不太好。

英文:

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) &lt; 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.

答案1

得分: 9

如果切片的长度大于2,你可以对其进行重新切片。如果不是,就不需要重新切片,直接在赋值中使用切片本身即可满足你的需求:结果将最多包含2个元素。

你甚至可以省略if语句的else分支:

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

注意:

切片是引用类型。所以即使你使用bar来初始化foo,如果之后修改了foo变量本身(而不是切片的元素),这不会影响到bar(在赋值时,引用值会被复制):

bar := []int{0, 1, 2, 3}
foo := bar
if len(foo) > 2 {
    foo = foo[:2]
}
fmt.Println(foo) // 这里的foo是预期的[0, 1]

foo = foo[:1]    // 对foo进行重新切片
fmt.Println(bar) // bar不受影响,bar = [0 1 2 3]

输出结果(在Go Playground上尝试):

[0 1]
[0 1 2 3]
英文:

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) &gt; 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) &gt; 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]

答案2

得分: 3

只需使用if语句。这样做更易读且性能更好,因为不需要在intfloat64之间进行转换。

var foo []int
if len(bar) > 1 {
    foo = bar[:2]
} else {
    foo = bar[:len(bar)]
}
英文:

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) &gt; 1 {
    foo = bar[:2]
} else {
    foo = bar[:len(bar)]
}

答案3

得分: 1

Go语言没有math.MinInt函数。但是实现一个类似的函数非常简单:

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

...

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

这段代码的作用是取bar切片的前两个元素,如果bar的长度小于2,则取整个切片。

英文:

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

func Min(x, y int) int {
	if x &lt; y {
		return x
	}
	return y
}

...

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

答案4

得分: 0

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

适用于 len(bar) = 0, 1, 2, n.. Playground 示例

英文:
bar := []int{}
n := len(bar)
if n &gt; 2 {
	n = 2
}
foo := bar[:n]
fmt.Printf(&quot;%v&quot;, foo)

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

答案5

得分: 0

通用(如您在评论中提问)的函数,适用于任意数量的元素:

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

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

Go Playground 示例

英文:

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

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

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

Go Playground example

huangapple
  • 本文由 发表于 2015年4月7日 21:12:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/29492505.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定