在slice中的index处添加单个值

时间:2017-09-09 06:56:30

标签: go slice

如果我有

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

我想在array2[2] 6之前插入array1[1]3,以便array1成为{1, 6, 3, 4, 5}的切片。我该怎么办?

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

8 个答案:

答案 0 :(得分:15)

您需要一个简单的append

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

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

应该{​​{1}},表示len(a) == index或空片或在最后一个元素之后追加:

nil

插入a = append(a, value) s的切片的索引零处:

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
}

对于OP:

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

基准:

    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]

代码:

len(a)==32:
BenchmarkInsert-8        6286105           203 ns/op         512 B/op          1 allocs/op
BenchmarkInsert2-8       5619445           214 ns/op         512 B/op          1 allocs/op

len(a)==1_000:
BenchmarkInsert-8         235446          4541 ns/op       16384 B/op          1 allocs/op
BenchmarkInsert2-8        240547          5143 ns/op       16384 B/op          1 allocs/op

len(a)==1_000_000:
BenchmarkInsert-8            381       2687634 ns/op    16007171 B/op          1 allocs/op
BenchmarkInsert2-8           428       2845477 ns/op    10002434 B/op          1 allocs/op

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

var a = make([]int, 32)
var r []int

func BenchmarkInsert(b *testing.B) {
    for i := 0; i < b.N; i++ {
        r = insert(a, 0, 1)
    }
}
func BenchmarkInsert2(b *testing.B) {
    for i := 0; i < b.N; i++ {
        r = insert2(a, 0, 1)
    }
}

func insert2(a []int, index int, value int) []int {
    a = append(a, a[len(a)-1])   // Step 1
    copy(a[index+1:], a[index:]) // Step 2
    a[index] = value             // Step 3
    return 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:]...) // Step 1+2
    a[index] = value                      // Step 3
    return a
}
  1. 这可确保阵列具有足够的容量来容纳新元素。
  2. 这会将所有必需的元素复制到更高的索引中,以为新元素腾出空间。
  3. 使用单个分配将元素设置在索引处: a = append(a[:index+1], a[index:]...)

根据基准,哪种方法更有效。

答案 1 :(得分:12)

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

  1. 确保array1有足够的容量(长度)来容纳新的可插入元素。要做到这一点,请使用构建append()附加单个元素(不管它是什么,它会被覆盖)。
  2. 要插入元素,现有元素必须移位(复制到更高的1索引)才能为该元素腾出空间,例如:使用内置copy()(之前想要插入的元素)。
  3. 使用单个assignment将元素设置为正确的索引。
  4. 在代码中:

    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]
    

答案 2 :(得分:3)

从@Volker扩展答案,如果你想测试它,我也把答案放在https://play.golang.org/p/3Hla2y2ava

package main

import "fmt"

func main() {
    array1 := []int{1, 3, 4, 5}
    array2 := []int{2, 4, 6, 8}
    temp := append([]int{array2[2]}, array1[1:]...)
    array1 = append(array1[:1], temp...)
    fmt.Println(array1)
}

答案 3 :(得分:1)

我发现问题设置非常棘手。

改写,他们想插入一个元素。在这里,我们有一个数组,其中缺少元素3,我们想将其插入。

package main

import (
    "fmt"
)

func main() {
    a := []int{1, 2, 4, 5, 6}
    b := 3

    // Make space in the array for a new element. You can assign it any value.
    a = append(a, 0)   
    fmt.Println(a)

    // Copy over elements sourced from index 2, into elements starting at index 3.
    copy(a[3:], a[2:])  
    fmt.Println(a)

    a[2] = b         
    fmt.Println(a)
}

答案 4 :(得分:1)

基于icza的帖子,我编写了一个函数来移动要与您共享的切片/数组:

package main

import "fmt"

func main() {
    s := []string{"a", "c", "d"}
    shiftArray(&s, 1, "b")
    fmt.Println(s)

}

func shiftArray(array *[]string, position int, value string) {
    //  extend array by one
    *array = append(*array, "")

    // shift values
    copy((*array)[position+1:], (*array)[position:])

    // insert value
    (*array)[position] = value
}

答案 5 :(得分:1)

以下解决方案对我有用

func insert(a []int, c int, i int) []int {
    return append(a[:i], append([]int{c}, a[i:]...)...)
}

您可以通过空界面使其更通用

func insert(a []interface{}, c interface{}, i int) []interface{} {
    return append(a[:i], append([]interface{}{c}, a[i:]...)...)
}

答案 6 :(得分:0)

我不知道它是否最佳,但是这段代码对我有用:

func sliceins(arr []int, pos int, elem int) []int { //insert element before pos in slice. if pos >= len(arr) insert into tail
    if pos < 0 {
        pos = 0
    } else if pos >= len(arr) {
        pos = len(arr)
    }
    out := make([]int, len(arr)+1)
    copy(out[:pos], arr[:pos])
    out[pos] = elem
    copy(out[pos+1:], arr[pos:])
    return out
}

以您为例,只需致电

sliceins(array1, 1, array2[2])

答案 7 :(得分:0)

我在其他线程中回答了类似的问题。无论如何,我使用以下方法来处理切片和索引:

func insertInt(array []int, value int, index int) []int {
    return append(array[:index], append([]int{value}, array[index:]...)...)
}

func removeInt(array []int, index int) []int {
    return append(array[:index], array[index+1:]...)
}

func moveInt(array []int, srcIndex int, dstIndex int) []int {
    value := array[srcIndex]
    return insertInt(removeInt(array, srcIndex), value, dstIndex)
}

您可以在这里玩它:

https://play.golang.org/p/Sfu1VsySieS

希望对您有帮助