在Golang中进行切片合并的建议

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

Slice merge in golang recommendation

问题

有没有办法让这段 Golang 代码更短?

func MergeSlices(s1 []float32, s2 []int32) []int {
    var slice []int
    for i := range s1 {
        slice = append(slice, int(s1[i]))
    }
    for i := range s2 {
        slice = append(slice, int(s2[i]))
    }
    return slice
}

有几种方法可以使这段代码更短。以下是一种可能的简化方式:

func MergeSlices(s1 []float32, s2 []int32) []int {
    slice := make([]int, len(s1)+len(s2))
    for i, v := range s1 {
        slice[i] = int(v)
    }
    for i, v := range s2 {
        slice[i+len(s1)] = int(v)
    }
    return slice
}

这种简化方式使用了 make 函数来创建一个足够容纳两个切片元素的新切片。然后,使用一个循环将 s1s2 中的元素转换为整数,并将它们放入新切片中。最后,返回新切片。

这样做可以减少代码行数,并且更加简洁。

英文:

Is there a way to make this golang code shorter?

func MergeSlices(s1 []float32, s2 []int32) []int {
	var slice []int
	for i := range s1 {
		slice = append(slice, int(s1[i]))
	}
	for i := range s2 {
		slice = append(slice, int(s2[i]))
	}
	return slice
}

答案1

得分: 5

你无法消除将每个元素单独转换为int的循环,因为你无法转换不同元素类型的整个切片。有关解释,请参阅此问题:https://stackoverflow.com/questions/12753805/type-converting-slices-of-interfaces-in-go

你能做的最多就是使用命名结果类型,并使用带有两个迭代值的for range循环,其中你可以通过将其赋值给空白标识符来省略第一个迭代值(索引),而第二个迭代值将是元素的值:

func MergeSlices(s1 []float32, s2 []int32) (s []int) {
    for _, v := range s1 {
        s = append(s, int(v))
    }
    for _, v := range s2 {
        s = append(s, int(v))
    }
    return
}

但要知道,你的代码原样也是可以的。我的代码并不是要一直遵循的规范,它只是回答你的问题:如何使你的代码更短。如果你想改进你的代码,你可以从性能方面入手,甚至重构你的代码,以避免最终需要合并不同类型的切片。

英文:

You can't eliminate the loops to convert each element to int individually, because you can't convert whole slices of different element types. For explanation, see this question: https://stackoverflow.com/questions/12753805/type-converting-slices-of-interfaces-in-go

The most you can do is use named result type, and a for range with 2 iteration values, where you can omit the first (the index) by assigning it to the blank identifier, and the 2nd will be the value:

func MergeSlices(s1 []float32, s2 []int32) (s []int) {
	for _, v := range s1 {
		s = append(s, int(v))
	}
	for _, v := range s2 {
		s = append(s, int(v))
	}
	return
}

But know that your code is fine as-is. My code is not something to always follow, it was to answer your question: how to make your code shorter. If you want to improve your code, you could start by looking at its performance, or even refactoring your code to not end up needing to merge slices of different types.

答案2

得分: 3

你的代码应该正确、可维护、可读,并且具有合理的效率。请注意,代码的简洁性并不是重要目标之一。出于充分的理由,Stack Exchange 有另一个网站专门用于 Code Golf 问题:Programming Puzzles & Code Golf

你的代码可以改进;它不够高效。例如,合并两个长度为 len(256) 的切片,

BenchmarkMergeSlices 	  200000	  8350 ns/op	8184 B/op	  10 allocs/op

下面是一个更高效(但更长)的版本:

BenchmarkMergeSlices 	  300000	  4420 ns/op	4096 B/op	   1 allocs/op

.

func MergeSlices(s1 []float32, s2 []int32) []int {
	slice := make([]int, 0, len(s1)+len(s2))
	for i := range s1 {
		slice = append(slice, int(s1[i]))
	}
	for i := range s2 {
		slice = append(slice, int(s2[i]))
	}
	return slice
}

使用Go 代码审查评论中的命名返回参数。例如:"不要仅仅为了避免在函数内部声明一个变量而给结果参数命名;这样做会以不必要的 API 冗长为代价换取轻微的实现简洁性。文档的清晰度总是比在函数中节省一两行代码更重要。"

英文:

Your code should be correct, maintainable, readable, and reasonably efficient. Note that shortness of code is not one of the important goals. For good reason, Stack Exchange has another site for Code Golf questions: Programming Puzzles & Code Golf.

Your code could be improved; it's inefficient. For example, merging two len(256) slices,

BenchmarkMergeSlices 	  200000	  8350 ns/op	8184 B/op	  10 allocs/op

Here's a more efficient (and longer) version:

BenchmarkMergeSlices 	  300000	  4420 ns/op	4096 B/op	   1 allocs/op

.

func MergeSlices(s1 []float32, s2 []int32) []int {
	slice := make([]int, 0, len(s1)+len(s2))
	for i := range s1 {
		slice = append(slice, int(s1[i]))
	}
	for i := range s2 {
		slice = append(slice, int(s2[i]))
	}
	return slice
}

Use the Go Code Review Comments for Named Result Parameters. For example: "Don't name result parameters just to avoid declaring a var inside the function; that trades off a minor implementation brevity at the cost of unnecessary API verbosity. Clarity of docs is always more important than saving a line or two in your function."

答案3

得分: 3

var s1 []int
var s2 []int

newSlice = append(s1, s2...)

变量 s1 是一个 int 类型的切片。
变量 s2 是一个 int 类型的切片。

newSlice 是将 s2 切片的元素追加到 s1 切片后形成的新切片。

英文:
var s1 []int
var s2 []int

newSlice = append(s1, s2...)

答案4

得分: 0

代码无法再变得更短了,但这本身就是一个值得怀疑的目标;它的现有形式并不过于冗长。然而,你可以通过消除中间分配来提高性能。每次调用append时,如果目标切片没有足够的空间,它会扩展它,并猜测所需的大小,因为你没有告诉它需要多少空间。

最简单的方法就是预设目标切片的大小(将var slice []int替换为slice := make([]int, 0, len(s1) + len(s2)));这样,追加操作就不需要再扩展它了。将第二个参数设置为0很重要,它将长度设置为零,容量设置为所需的总大小,这样你的追加操作就能按预期工作。

一旦你预设了大小,你可以完全摒弃追加操作,直接设置每个索引:

func MergeSlices(s1 []float32, s2 []int32) []int {
    slice := make([]int, len(s1) + len(s2))
    for i,v := range s1 {
        slice[i] = int(v)
    }
    for i,v := range s2 {
        slice[i+len(s1)] = int(v)
    }
    return slice
}

Playground链接

英文:

The code can't get any shorter, but that's a goal of dubious value to begin with; it's not overly verbose as-is. You can, however, likely improve performance by eliminating the intermediate allocations. Every time you call append, if the target slice doesn't have enough space, it expands it, guessing at the necessary size since you haven't told it how much space it will need.

The simplest would just be to presize your target slice (replace var slice []int with slice := make([]int, 0, len(s1) + len(s2)); that way the appends never have to expand it. Setting the second parameter to 0 is important, that sets the length to zero, and the capacity to the total size needed, so that your appends will work as expected.

Once you've presized it though, you can get rid of the appends entirely, and directly set each index:

func MergeSlices(s1 []float32, s2 []int32) []int {
	slice := make([]int, len(s1) + len(s2))
	for i,v := range s1 {
		slice[i] = int(v)
	}
	for i,v := range s2 {
		slice[i+len(s1)] = int(v)
	}
	return slice
}

Playground link

huangapple
  • 本文由 发表于 2017年5月12日 17:13:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/43933824.html
匿名

发表评论

匿名网友

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

确定