0

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

blackgreen
  • 34,072
  • 23
  • 111
  • 129
Tobias Meyer
  • 345
  • 1
  • 3
  • 10

2 Answers2

3

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:

playground link

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.

captncraig
  • 22,118
  • 17
  • 108
  • 151
0

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)
TehSphinX
  • 6,536
  • 1
  • 24
  • 34