在给定索引处的切片中插入一个值

新手上路,请多包涵

鉴于

array1 := []int{1, 3, 4, 5}
array2 := []int{2, 4, 6, 8}

I want to insert array2[2] ie 6 at array1[1] ie before 3 so that array1 becomes a slice of {1, 6, 3, 4, 5} 。我该怎么做?

我在网上阅读的大多数技术都涉及使用 : 运算符,但也会导致插入剩余元素。如何在切片的索引处附加单个值?

原文由 chefcurry7 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 461
2 个回答

简单,高效和合乎逻辑的方式:

  1. 确保 array1 有足够的容量(长度)来容纳新的可插入元素。为此,请使用 append() 添加单个元素(不管那是什么,它都会被覆盖)。
  2. 要插入元素,必须 移动 现有元素(复制到高 1 个索引)以为该元素腾出空间,例如使用内置 copy() (您要在之前插入的元素)。
  3. 使用单个 赋值 将元素设置在适当的索引处。

在代码中:

 array1 := []int{1, 3, 4, 5}
array2 := []int{2, 4, 6, 8}

array1 = append(array1, 0)   // Step 1
copy(array1[2:], array1[1:]) // Step 2
array1[1] = array2[2]        // Step 3

fmt.Println(array1)

输出(在 Go Playground 上尝试):

 [1 6 3 4 5]

特殊情况下的优化

请注意,在某些特殊情况下(当 slice 元素很大时,比如一个大结构),追加最后一个元素可能会更快,然后复制少 1 个元素就足够了(因为追加的最后一个元素就在它需要的地方成为)。

这是它的样子:

 last := len(array1) - 1
array1 = append(array1, array1[last]) // Step 1
copy(array1[2:], array1[1:last])      // Step 2
array1[1] = array2[2]                 // Step 3

这将产生相同的切片。在 Go Playground 试试这个。

原文由 icza 发布,翻译遵循 CC BY-SA 4.0 许可协议

一个简单的 append 就是你所需要的:

 a = append(a[:index+1], a[index:]...)
a[index] = value

注意: len(a) > 0 && index < len(a)

应该 len(a) == index ,意思是 nil 或空切片或追加在最后一个元素之后:

 a = append(a, value)

int 的切片的索引零处插入:

 a = append([]int{value}, a...)


一站式功能:

 // 0 <= index <= len(a)
func insert(a []int, index int, value int) []int {
    if len(a) == index { // nil or empty slice or after last element
        return append(a, value)
    }
    a = append(a[:index+1], a[index:]...) // index < len(a)
    a[index] = value
    return a
}

用法:

     a := []int{10, 30, 40}
    a = insert(a, 1, 20)
    fmt.Println(a) // [10 20 30 40]

对于OP:

     slice1 := []int{1, 3, 4, 5}
    slice2 := []int{2, 4, 6, 8}
    // slice1 = insert(slice1, 1, slice2[2])
    slice1 = append(slice1[:2], slice1[1:]...)
    slice1[1] = slice2[2]

    fmt.Println(slice1) // [1 6 3 4 5]


基准:

 go version
# go version go1.16.3 linux/amd64
make bench
go test -benchmem -bench . -args -n 32
# BenchmarkInsert-8      4125085  275.0 ns/op  512 B/op  1 allocs/op
# BenchmarkInsert2-8     3778551  316.0 ns/op  512 B/op  1 allocs/op

go test -benchmem -bench . -args -n 1000
# BenchmarkInsert-8       198364  5876 ns/op  16384 B/op  1 allocs/op
# BenchmarkInsert2-8      205197  7123 ns/op  16384 B/op  1 allocs/op

go test -benchmem -bench . -args -n 1000000
# BenchmarkInsert-8          643  1898436 ns/op 10002437 B/op  1 allocs/op
# BenchmarkInsert2-8         368  3248385 ns/op 10002436 B/op  1 allocs/op

代码:

 func insert(a []int, index int, value int) []int {
    a = append(a[:index+1], a[index:]...) // Step 1+2
    a[index] = value                      // Step 3
    return a
}
func insert2(a []int, index int, value int) []int {
    last := len(a) - 1
    a = append(a, a[last])           // Step 1
    copy(a[index+1:], a[index:last]) // Step 2
    a[index] = value                 // Step 3
    return a
}
func BenchmarkInsert(b *testing.B) {
    for i := 0; i < b.N; i++ {
        r = insert(a, 2, 42)
    }
}
func BenchmarkInsert2(b *testing.B) {
    for i := 0; i < b.N; i++ {
        r = insert2(a, 2, 42)
    }
}

var (
    n    = flag.Int("n", 32, "buffer length")
    a, r []int
)

// We use TestMain to set up the buffer.
func TestMain(m *testing.M) {
    flag.Parse()
    a = make([]int, *n)
    os.Exit(m.Run())
}

您可以将前 两个 步骤合并为 一个;通过使用:

     a = append(a[:index+1], a[index:]...)

  1. 这确保数组有足够的容量来容纳新元素。
  2. 这会将所有必需的元素复制到更高的索引,以便为新元素腾出空间。
  3. 使用单个赋值在索引处设置元素: a[index] = value

根据基准,哪个更有效。

原文由 wasmup 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题