Fill a slice with values

22,950 views
Skip to first unread message

Kowshik Prakasam

unread,
Sep 25, 2012, 8:43:21 PM9/25/12
to golan...@googlegroups.com
// assume that arr is a slice of integers.
for index, _ := range arr {
    arr[index] = 0
}

Is there an alternative to the above code?
For example, Java provides the Arrays.fill(...) method.



-Kowshik

RoboTamer

unread,
Sep 25, 2012, 8:53:46 PM9/25/12
to golan...@googlegroups.com
I don't believe there is, but you could write that method in go then there will be one for go too  ;) 

Daniel Jo

unread,
Sep 25, 2012, 9:23:47 PM9/25/12
to Kowshik Prakasam, golan...@googlegroups.com
Go automatically zeros all new variables and newly allocated memory. Thus, the following will fill arr with zeroes:

copy(arr, make([]int, len(arr)))

However, this involves an allocation, while your loop does not. Furthermore, it is only good for applying zero values. Really, the only "advantage" is that it is a single line of code.

One could conceivably create a generic helper function via reflection, but it would be be much slower than a function specifically tailored to the slice type. Just for fun:

func fill(slc, val interface{}) {
    sv := reflect.ValueOf(slc)
    if sv.Kind() != reflect.Slice {
        panic("fill: slc expected slice")
    }

    vv := reflect.ValueOf(val)
    if vv.Type() != sv.Type().Elem() {
        panic("fill: val type != slc element type")
    }

    for i := 0; i < sv.Len(); i++ {
        sv.Index(i).Set(vv)
    }
}

Barring the introduction of generics or a generic builtin, your best choice is a tailored loop, such as you presented.

-Daniel




-Kowshik

--
 
 



--
--Ostsol

http://cheesesun.blogspot.com/

Dmitry Chestnykh

unread,
Sep 25, 2012, 10:33:34 PM9/25/12
to golan...@googlegroups.com
On Wednesday, September 26, 2012 2:43:28 AM UTC+2, Kowshik Prakasam wrote:
// assume that arr is a slice of integers.
for index, _ := range arr {
    arr[index] = 0
}

Is there an alternative to the above code?

There is:

for i := range arr {
    arr[i] = 0
}
 

Patrick Mylund Nielsen

unread,
Sep 25, 2012, 11:33:02 PM9/25/12
to Kowshik Prakasam, golan...@googlegroups.com
If you just want a new array/slice of 30 zeroes: s := make([]int, 30, 30)  (See docs for make: http://golang.org/ref/spec#Slice_types, length and capacity)

If you want to zero out an existing slice/array, then: for i := range s { s[i] = 0 }  This code is clean and doesn't hide the fact that the operation is O(n).

To empty a slice without allocating a new array: s = s[:0]




-Kowshik

--
 
 

Sebastien Binet

unread,
Sep 26, 2012, 2:25:11 AM9/26/12
to Patrick Mylund Nielsen, golan...@googlegroups.com, Kowshik Prakasam

Hi,

I am not very knowledgeable in that area, but wouldn't the copy-based version be more amenable to compiler optimization (think simd, avx,...) than the for-loop one ?

-s

-- sent from my droid --

--
 
 

RoboTamer

unread,
Sep 26, 2012, 2:31:50 AM9/26/12
to golan...@googlegroups.com
I got inspired by your question and created a fill method, but didn't stop there.
See my announcement at

Patrick Mylund Nielsen

unread,
Sep 26, 2012, 2:41:36 AM9/26/12
to Sebastien Binet, golan...@googlegroups.com, Kowshik Prakasam
It's probably more accurate to think of copy(s, make([]int, len(s))) as just s = make([]int, len(s)). The loop changes the values of an existing array to 0.

minux

unread,
Sep 26, 2012, 12:06:36 PM9/26/12
to Patrick Mylund Nielsen, Sebastien Binet, golan...@googlegroups.com, Kowshik Prakasam

On Wednesday, September 26, 2012, Patrick Mylund Nielsen wrote:
It's probably more accurate to think of copy(s, make([]int, len(s))) as just s = make([]int, len(s)). The loop changes the values of an existing array to 0.
However, these two forms are not equivalent.
Other slices might share original s' backing array.

André Moraes

unread,
Sep 26, 2012, 12:15:35 PM9/26/12
to Kowshik Prakasam, golan...@googlegroups.com
package main

import "fmt"

func zero(arr *[]int) {
*arr = make([]int, len(*arr))
}

func main() {
arr := make([]int, 10)
for i, _ := range arr {
arr[i] = i
}
fmt.Printf("arr: %v\n", arr)
zero(&arr)
fmt.Printf("arr: %v\n", arr)
}


This code zero's the slice and you don't need to do any copy/iteration.

--
André Moraes
http://amoraes.info

Patrick Mylund Nielsen

unread,
Sep 26, 2012, 12:28:29 PM9/26/12
to André Moraes, Kowshik Prakasam, golan...@googlegroups.com
It also allocates a new array. That's hardly ideal when the slice/array is huge, but then you'd probably be better off not zeroing it, anyway. If you just want to re-use an array, all you need is an offset field that specifies the end of the "valid"/active part, or to empty the slice and use the same underlying array.

--



Patrick Mylund Nielsen

unread,
Sep 26, 2012, 12:30:27 PM9/26/12
to minux, Sebastien Binet, golan...@googlegroups.com, Kowshik Prakasam
But you're still allocating a new array, right?

minux

unread,
Sep 26, 2012, 12:47:16 PM9/26/12
to Patrick Mylund Nielsen, Sebastien Binet, golan...@googlegroups.com, Kowshik Prakasam

On Thursday, September 27, 2012, Patrick Mylund Nielsen wrote:
But you're still allocating a new array, right?
True, so I don't recommend that form although it is shorter than
its alternative.
Reply all
Reply to author
Forward
0 new messages