Go中的惯用切片拼接?

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

Idiomatic slice splice in Go?

问题

我有以下代码来实现一个splice(即给定一个字节切片full,另一个字节切片part,以及一个表示我想要用part覆盖full中位置的整数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个字节切片连接起来:full中不被part覆盖的第一部分,整个part,然后是full的剩余部分。有没有更好/更惯用的方法来做到这一点?我在标准库中没有找到实现这个的方法。

英文:

I have the following code for implementing a splice (that is, given a byte slice full, another byte slice part, and an int pos representing the position in full that I want to overwrite with part):

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{})
}

Basically, my method does a join of 3 byte slices: the first part of full that doesn't get overwritten by part, all of part, and then the remaining part of full. Is there a better/more idiomatic way of doing this? I wasn't able to find a method that implemented this in the standard library.

答案1

得分: 6

如果你知道部分完全在完整范围内,你可以使用copy函数。

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

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

这会覆盖full。如果你想保留原始值,你可以先用append函数进行复制。

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)
}

请注意,这仍然有你原始代码的限制,即part必须适合full的范围内。

英文:

If you know part is completely within the bounds of full, you can use the copy function.

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

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

playground

That overwrites full though. If you wanted to preserve the original, you could make a copy first with the append function.

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

Note that this still has the limitation of your original code that part must fit within the bounds of full.

答案2

得分: 1

为什么不使用内置的append函数?

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

这可能不是非常快(有很多复制),但它非常易读。

英文:

Why not use the append built-in?

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

This may not be very fast (lots of copying), but it's pretty readable.

答案3

得分: 1

这里是另一种拼接字节切片的变体。算法与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")
}

我还包含了一组测试用例。

英文:

Here is another variant for splicing byte slices. The algorithm is similar to Anton Litvinov's stringSplice(). Because the append function shares the same slice as the input, a copy of the same length as the input must be used. This was not done by 'beatgammit' in the previous answer, which does not work correctly.

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")
}

I have also included a group of test cases

答案4

得分: 0

一个字符串的变体(分割/拼接/连接)。

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:]
}
英文:

A variant for string (split / splice / join).

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:]
}

huangapple
  • 本文由 发表于 2012年11月25日 02:45:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/13544374.html
匿名

发表评论

匿名网友

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

确定