【问题标题】:Idiomatic slice splice in Go?Go中惯用的切片拼接?
【发布时间】:2012-11-24 18:45:40
【问题描述】:

我有以下代码用于实现拼接(即,给定一个完整的字节切片、另一个字节切片部分和一个表示我想用部分覆盖的完整位置的 int pos):

package main

import (
    "fmt"
    "bytes"
)

func main() {
    full := []byte{0,0,0,0,0,0,0}
    part := []byte{1,1,1}

    newFull1 := splice(full, part, 2)
    fmt.Println(newFull1)
    // [0 0 1 1 1 0 0]

    newFull2 := splice(full, part, 3)
    fmt.Println(newFull2)
    // [0 0 0 1 1 1 0]
}

func splice(full []byte, part []byte, pos int) []byte {
    return bytes.Join([][]byte{full[:pos], part, full[len(full[:pos])+len(part):]}, []byte{})
}

基本上,我的方法执行 3 字节切片的连接:完整的第一部分不会被部分覆盖,全部部分,然后是完整的剩余部分。有没有更好/更惯用的方法来做到这一点?我无法在标准库中找到实现此功能的方法。

【问题讨论】:

  • 我觉得不错。我认为您不会找到更简洁的方法来完成此操作。不过,您可能想要添加错误检查。 pos 可能超出范围。

标签: go


【解决方案1】:

如果你知道部分完全在full范围内,你可以使用复制功能。

func main() {
    full := []byte{0, 0, 0, 0, 0, 0, 0}
    part := []byte{1, 1, 1}

    copy(full[2:], part)
    fmt.Println(full)
}

playground

这会覆盖完整的。如果您想保留原件,可以先使用附加功能进行复制。

func main() {
    full := []byte{0, 0, 0, 0, 0, 0, 0}
    part := []byte{1, 1, 1}

    newFull := append([]byte{}, full...)
    copy(newFull[2:], part)
    fmt.Println("newFull:      ", newFull)
    fmt.Println("original full:", full)
}

playground

请注意,这仍然有原始代码的限制,该部分必须适合完整的范围。

【讨论】:

    【解决方案2】:

    这是拼接字节切片的另一种变体。该算法类似于 Anton Litvinov 的 stringSplice()。因为 append 函数与输入共享相同的切片,所以必须使用与输入相同长度的副本。这不是由上一个答案中的“beatgammit”完成的,它不能正常工作。

    package main
    
    import "fmt"
    
    func sliceSplice(input []byte, start, deleteCount int, item []byte) ([]byte) {
        fmt.Printf("input:      %v start = %d deleteCount = %d item: %v\n", input, start, deleteCount, item)
        cpy := make([]byte, len(input))
        copy(cpy, input)
        fmt.Println("cpy:       ", cpy)
        if start > len(cpy) {
            return append(cpy, item...)
        }
        ret := append(cpy[:start], item...)
        fmt.Println("ret:       ", ret)
    
        if start+deleteCount > len(cpy) {
            return ret
        }
        fmt.Println("cpy:       ", cpy, "       modified by shared slice 'ret'")
        fmt.Println("input[s+d] ", input[start+deleteCount:], "         not modified")
        return append(ret, input[start+deleteCount:]...)
    }
    
    func main() {
        oldFull := []byte{0, 0, 1, 1, 1, 0, 0}
        fmt.Println("oldFull:      ", oldFull, "\n")
        myFull := sliceSplice(oldFull, 3, 0, []byte{2, 2})
        fmt.Println("myFull:       ", myFull, "\n")
        myFull = sliceSplice(oldFull, 3, 1, []byte{2, 2})
        fmt.Println("myFull:       ", myFull, "\n")
        myFull = sliceSplice(oldFull, 3, 4, []byte{2, 2})
        fmt.Println("myFull:       ", myFull, "\n")
        myFull = sliceSplice(oldFull, 3, 6, []byte{2, 2})
        fmt.Println("myFull:       ", myFull, "\n")
        myFull = sliceSplice(oldFull, 7, 0, []byte{2, 2})
        fmt.Println("myFull:       ", myFull, "\n")
        myFull = sliceSplice(oldFull, 9, 6, []byte{2, 2})
        fmt.Println("myFull:       ", myFull, "\n")
    }
    

    我还包括了一组测试用例

    【讨论】:

      【解决方案3】:

      为什么不使用内置的append

      func splice(full, part []byte, pos int) (ret []byte) {
          ret = append(full[:pos], part...)
          return append(ret, full[pos:]...)
      }
      

      这可能不是很快(大量复制),但它的可读性很好。

      【讨论】:

        【解决方案4】:

        字符串的变体(拆分/拼接/连接)。

        func stringSplice(full string, start, deleteCount int, item string) (ret string) {
            if start > len(full) {
                return full + item
            }
            ret = full[:start] + item
        
            if start+deleteCount > len(full) {
                return ret
            }
            return ret + full[start+deleteCount:]
        }
        

        【讨论】:

          猜你喜欢
          • 2017-08-02
          • 1970-01-01
          • 2018-04-24
          • 1970-01-01
          • 2014-01-19
          • 2013-04-21
          • 2016-07-17
          • 2016-05-12
          相关资源
          最近更新 更多