Reputation: 145
I just started playing with Go. I started creating a function that accepts an array of integers and returning the chunks of that array. To see what I mean, here is that program:
package main
import (
"fmt"
"math"
)
func main() {
a:= []int{1,2,3,4,5,6,2, 231, 521,21, 51}
c:=chunks(a[:], 3)
fmt.Println(c) // [[1 2 3] [4 5 6] [2 231 521] [51]]
}
func chunks(a []int, size int) [][]int{
var f float64 = float64(len(a)) / float64(size)
size_of_wrapper := int(math.Ceil(f))
i := 0
j := 0
twoD := make([][]int, size_of_wrapper )
for i < len(a) {
if i + size < len(a) {
twoD[j] = make([]int, size)
twoD[j] = append(a[i:i+size])
i = i + size
j++
} else {
if i + size == len(a){
i++
} else {
twoD[j] = make([]int, 1)
twoD[j] = append(a[len(a)-1:])
i++
}
}
}
return twoD
}
Now, I have a question. Can I turn this function to be able to receive an array that has strings in it or any other types? Also, can I set to return that same type at the end? In this case, I return an array of arrays that contain only integer values.
I seem to really struggle to find the solution to this problem. One of the posts that I have read recommended to use interface type for this kind of job. Is that the only one?
Upvotes: 1
Views: 133
Reputation: 120941
Because Go does not yet have the generics, the options are to use reflection or to duplicate code for each type. Here's how to use the reflect package:
// chunkAny slices a into size chunks and puts result in cp.
// The variable cp must be pointer to slice of a's type.
func chunkAny(a interface{}, size int, cp interface{}) {
av := reflect.ValueOf(a)
cv := reflect.ValueOf(cp).Elem()
cv.SetLen(0) // reset length in case backing array allocated
i, j := 0, size
for j < av.Len() {
cv.Set(reflect.Append(cv, av.Slice(i, j)))
i += size
j += size
}
cv.Set(reflect.Append(cv, av.Slice(i, av.Len())))
}
Call the function like this:
a := []string{"a", "b", "c", "d"}
var b [][]string
chunkAny(a, 3, &b)
Upvotes: 1
Reputation: 139
Can I turn this function to be able to receive an array that has strings in it or any other types? Also, can I set to return that same type at the end? I
Unfortunately the Go programming language does not have generics. AFAIK Go will have generics in the next 2.0 release so right now you mainly have 3 maybe 4 options.
[]interface{}
typeYour function declaration will look something like this.
func chunks(a []interface{}, size int) [][]interface{}
Using this approach will imply some type assertion.
The definition will look the same but this time in your implementation, instead of using the type assertion technique you will use the reflect package to determine your type and retrieve values. Remember you will pay a reasonable cost using this approach.
You could use this generic pointer type and do some pointer arithmetic in a C spirit way.
func chunks(a unsafe.Pointer, len uintptr, size uintptr) unsafe.Pointer
I know if you search Go does not oficially support doing pointer arithmetic but you can fake it using tricks like.
package main
import "fmt"
import "unsafe"
func main() {
vals := []int{10, 20, 30, 40}
start := unsafe.Pointer(&vals[0])
size := unsafe.Sizeof(int(0))
for i := 0; i < len(vals); i++ {
item := *(*int)(unsafe.Pointer(uintptr(start) + size*uintptr(i)))
fmt.Println(item)
}
}
You can find more information on how to generate go code base on what types you provide.
Upvotes: 1