在就地功能内更改切片内容和容量

时间:2017-07-23 20:14:28

标签: go slice in-place

我正在努力学习Go,所以这是我非常简单的功能,可以从Donovan& amp;书中删除相关的重复片段。 Kernighan的。
以下是代码:https://play.golang.org/p/avHc1ixfck

package main
import "fmt"

func main() {
    a := []int{0, 1, 1, 3, 3, 3}
    removeDup(a)
    fmt.Println(a)
}

func removeDup(s []int) {
    n := len(s)
    tmp := make([]int, 0, n)
    tmp = append(tmp, s[0])
    j := 1
    for i := 1; i < n; i++ {
        if s[i] != s[i-1] {
            tmp = append(tmp, s[i])
            j++
        }
    }
    s = s[:len(tmp)]
    copy(s, tmp)
}

它应该打印出[0 1 3] - 我检查了,实际上tmp在它所需的功能结束时。但是,结果是[0 1 3 3 3 3]。我猜有copy函数。

我能否以某种方式将输入切片s替换为temp或将其修剪为所需的长度?

2 个答案:

答案 0 :(得分:4)

选项1

按照@zerkms的建议返回一个新切片 https://play.golang.org/p/uGJiD3WApS

package main
import "fmt"

func main() {
    a := []int{0, 1, 1, 3, 3, 3}
    a = removeDup(a)
    fmt.Println(a)
}

func removeDup(s []int) []int {
    n := len(s)
    tmp := make([]int, 0, n)
    tmp = append(tmp, s[0])
    for i := 1; i < n; i++ {
        if s[i] != s[i-1] {
            tmp = append(tmp, s[i])
        }
    }
    return tmp
}

选项2
使用指针进行传递引用。
与option1的效果相同。

https://play.golang.org/p/80bE5Qkuuj

package main

import "fmt"

func main() {
    a := []int{0, 1, 1, 3, 3, 3}
    removeDup(&a)
    fmt.Println(a)
}

func removeDup(sp *[]int) {
    s := *sp
    n := len(s)
    tmp := make([]int, 0, n)
    tmp = append(tmp, s[0])
    for i := 1; i < n; i++ {
        if s[i] != s[i-1] {
            tmp = append(tmp, s[i])
        }
    }
    *sp = tmp
}

另外,请参阅以下SO线程: Does Go have no real way to shrink a slice? Is that an issue?

答案 1 :(得分:0)

这是使用集合和命名类型实现所需内容的两种稍微不同的方法。关于命名类型的一个很酷的事情是你可以在它们周围创建接口,并且可以帮助提供大量代码的可读性。

package main

import "fmt"

func main() {
    // returning a list
    a := []int{0, 1, 1, 3, 3, 3}
    clean := removeDup(a)
    fmt.Println(clean)
    // creating and using a named type
    nA := &newArrType{0, 1, 1, 3, 3, 3}
    nA.removeDup2()
    fmt.Println(nA)

    // or... casting your orginal array to the named type
    nB := newArrType(a)
    nB.removeDup2()
    fmt.Println(nB)
}

// using a set
// order is not kept, but a set is returned
func removeDup(s []int) (newArr []int) {
    set := make(map[int]struct{})
    for _, n := range s {
        set[n] = struct{}{}
    }
    newArr = make([]int, 0, len(set))
    for k := range set {
        newArr = append(newArr, k)
    }
    return
}

// using named a typed
type newArrType []int

func (a *newArrType) removeDup2() {
    x := *a
    for i := range x {
        f := i + 1
        if f < len(x) {
            if x[i] == x[f] {
                x = x[:f+copy(x[f:], x[f+1:])]
            }
        }
    }
    // check the last 2 indexes
    if x[len(x)-2] == x[len(x)-1] {
        x = x[:len(x)-1+copy(x[len(x)-1:], x[len(x)-1+1:])]
    }
    *a = x
}