英文:
Helper function to chunk any slice?
问题
我创建了一个小的辅助函数,用于将一个包含大量项目的数组拆分为最大大小为n
的小数组。
func toPackages(e []int, n int) [][]int {
var p [][]int
packets := int(math.Ceil(float64(len(e)) / float64(n)))
for i := 0; i < packets; i++ {
start := i * n
end := n * (i + 1)
if len(e) < end {
end = len(e)
}
p = append(p, e[start:end])
}
return p
}
在Golang Playground上有一个工作示例。在程序中,我有几种不同类型的数组需要拆分。我尝试将其转换为使用interface{}
接口。
英文:
I created a small helper function to split a large array of items into smaller arrays with a maximum size of n
.
func toPackages(e []int, n int) [][]int {
var p [][]int
packets := int(math.Ceil(float64(len(e)) / float64(n)))
for i := 0; i < packets; i++ {
start := i * n
end := n * (i + 1)
if len(e) < end {
end = len(e)
}
p = append(p, e[start:end])
}
return p
}
Working example at Golang Playground.
In the program I have several different types of arrays I would like to split. I have tried converting it to using interfaces with interface{}
.
答案1
得分: 3
很难编写一个通用函数来很好地处理这个问题。你经常会花费很多代码将[]int
转换为[]interface{}
,然后再转换回来,而这与仅仅复制代码片段所需的代码量相当。不过,我有一种稍微更好的方法:
func splitInts(src []int, n int) (p [][]int){
for len(src) > n{
p = append(p,src[:n])
src = src[n:]
}
if(len(src) > 0){
p = append(p,src)
}
return p
}
函数中的任何内容都不会因为类型而改变,可以轻松地复制到:
func splitStrings(src []string, n int) (p [][]string){
for len(src) > n{
p = append(p,src[:n])
src = src[n:]
}
if(len(src) > 0){
p = append(p,src)
}
return p
}
只需更改第一行即可。
英文:
It is pretty hard to make a generic function to handle this well. You will often spend as much code converting []int
to []interface{}
and back, as it is to just copy the snippet. I do have a slightly nicer way to do it though:
func splitInts(src []int, n int) (p [][]int){
for len(src) > n{
p = append(p,src[:n])
src = src[n:]
}
if(len(src) > 0){
p = append(p,src)
}
return p
}
Nothing in the function changes because of types, it can easily be copied to:
func splitStrings(src []string, n int) (p [][]string){
for len(src) > n{
p = append(p,src[:n])
src = src[n:]
}
if(len(src) > 0){
p = append(p,src)
}
return p
}
By only changing the first line.
答案2
得分: 0
通常,对于每种类型,直接编写所需的函数是一个好主意。这也涉及到速度的问题:如果使用反射来编写通用函数,它的速度不会很快。
如果你仍然想要一个通用函数,可以使用以下代码:
func genToPackages(e interface{}, n int) interface{} {
t := reflect.TypeOf(e)
if t.Kind() != reflect.Slice {
log.Println("e必须是一个切片")
}
v := reflect.ValueOf(e)
packets := int(math.Ceil(float64(v.Len()) / float64(n)))
p := reflect.MakeSlice(reflect.SliceOf(t), packets, packets)
for i := 0; i < packets; i++ {
s := reflect.MakeSlice(t, n, n)
start := i * n
for j := 0; j < n; j++ {
s.Index(j).Set(v.Index(j+start))
}
p.Index(i).Set(s)
}
return p.Interface()
}
你需要将结果转换为你期望的类型。例如:
res := genToPackages([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5).([][]int)
请注意,这只是一个示例,你需要根据你的实际需求进行适当的修改。
英文:
Generally it is a good idea to just write the function for every type you need it for. This is also a matter of speed: if you use reflect to write a generic function it will not be as fast.
If you still want a generic function here it is:
func genToPackages(e interface{}, n int) interface{} {
t := reflect.TypeOf(e)
if t.Kind() != reflect.Slice {
log.Println("e has to be a slice")
}
v := reflect.ValueOf(e)
packets := int(math.Ceil(float64(v.Len()) / float64(n)))
p := reflect.MakeSlice(reflect.SliceOf(t), packets, packets)
for i := 0; i < packets; i++ {
s := reflect.MakeSlice(t, n, n)
start := i * n
for j := 0; j < n; j++ {
s.Index(j).Set(v.Index(j+start))
}
p.Index(i).Set(s)
}
return p.Interface()
}
You will have to cast the result to the type you expect. For example:
res := genToPackages([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5).([][]int)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论