Golang convert interface{} to array of N size - arrays

I have an array of T wrapped in an interface. I know the size of the array beforehand. How do I write a generic function that gets back an array (or a slice) for any array length? E.g. for size 3 I want something like
var values interface{} = [3]byte{1, 2, 3}
var size = 3 // I know the size
var _ = values.([size]byte) // wrong, array bound must be a const expression
I can't really do a type switch because [1]byte is a different type from [2]byte etc so I'd have to explicitly enumerate all possible sizes.

Reflect is your friend here:
package main
import (
"fmt"
"reflect"
)
func main() {
var in interface{} = [3]byte{1, 2, 3} // an element from your []interface{}
var size = 3 // you got this
out := make([]byte, size) // slice output
for i := 0; i < size; i++ {
idxval := reflect.ValueOf(in).Index(i) // magic here
uidxval := uint8(idxval.Uint()) // you may mess around with the types here
out[i] = uidxval // and dump in output
}
fmt.Printf("%v\n", out)
}
Slices are the better choice output here, since you indicate that you have an undefined length.
What Magic here does is indexing the value of your input interface through reflect. This is not quick, but it does the trick.

Related

How to concatenate two arrays in Go

A basic question that I'm struggling to find an answer for as there are a lot of answers about how to join two slices using the append function and the spread operator which erroneously use the word 'array'.
I am new to Go and have made the assumption that using sized arrays is good practice where the size is known. However I am struggling to work with arrays as I can't figure out how to do simple operations such as concatenation. Here is some code.
var seven [7]int
five := [5]int{1,2,3,4,5}
two := [2]int{6,7}
//this doesn't work as both the inputs and assignment are the wrong type
seven = append(five,two)
//this doesn't work as the assignment is still the wrong type
seven = append(five[:],two[:])
//this works but I'm not using arrays anymore so may as well use slices everywhere and forget sizing
seven2 := append(five[:],two[:])
As far as I can see I can either just give up on arrays and use slices exclusively or I could write a loop to explicitly construct the new array. Is there a third option?
append() can only be used to append elements to a slice. If you have an array, you can't pass that directly to append().
What you may do is slice the array, so you get a slice (which will use the array as its backing store), and you can use that slice as the target and source of elements.
For example:
s := seven[:0]
s = append(s, five[:]...)
s = append(s, two[:]...)
fmt.Println(seven)
This will print (try it on the Go Playground):
[1 2 3 4 5 6 7]
Also note that since append() returns the resulting slice, it's possible to write all this in one line:
_ = append(append(seven[:0], five[:]...), two[:]...)
(Storing the result is not needed here because we have and want to use only the backing array, but in general that is not the case.)
This outputs the same, try it on the Go Playground. Although this isn't very readable, so it's not worth compacting it into a single line.
Although when you have the target array, "appending" arrays is nothing more than copying them to the target, to the proper position. For that, you may use the builtin copy() function too. Note that the copy() function also accepts only slices, so you have to slice the arrays here too.
copy(seven[:], five[:])
copy(seven[len(five):], two[:])
fmt.Println(seven)
This will output the same. Try this one on the Go Playground.
You can use copy
copy(seven[:], five[:])
copy(seven[5:], two[:])
fmt.Printf("%v\n", seven)
> [1 2 3 4 5 6 7]
You can concatenate two arrays in go using copy function
package main
import "fmt"
func main() {
five := [5]int{1, 2, 3, 4, 5}
two := [2]int{6, 7}
var n [len(five) + len(two)]int
copy(n[:], five[:])
copy(n[len(five):], two[:])
fmt.Println(n)
}
https://blog.golang.org/go-slices-usage-and-internals
Golang runtime used to check whether current index exceeds the maximum possible.
On the side of array, it look ups its type (which contain its len and reference to the element type), because that's type, that can be registered only at compile time.
// each array mention with unique size creates new type
array := [5]byte{1,2,3,4,5}
On the side of slice, it look ups their header which looks like:
type slice {
data *byte
len int
cap int // capacity, the maximum possible index
}
As you can see, any slice is a single structure with data and len, cap fields, meanwhile array is just single pointer to data (*byte).
When you trying to convert array to slice, it just creates slice header and fills fields with:
slice := array[:]
==
slice := Slice{}
slice.data = array
slice.len = type_of(array).len
slice.cap = type_of(array).len
you can do that simply by converting array into slice:
arr1 := [...]int {1,2,3,}
arr2 := [...]int {4,5,6, }
//arr3 = arr1 + arr2 // not allowed
// converting arrays into slice
slc_arr1, slc_arr2 := arr1[:], arr2[:]
slc_arr3 := make([]int, 0)
slc_arr3 = append(slc_arr1, slc_arr2...)
fmt.Println(slc_arr3) // [1 2 3 4 5 6]
There is a more general way of appending an array of any type(once Golang has generics, but for now this solution is specific to strings. Just change the type as appropriate). The notion of Fold comes from Functional Programming. Note I have also included a filter function which also uses Fold. The solution is not stack safe but in many cases that does not matter. It can be made stack safe with trampolining. At the end is an example of its usage.
func FoldRightStrings(as, z []string, f func(string, []string) []string) []string {
if len(as) > 1 { //Slice has a head and a tail.
h, t := as[0], as[1:len(as)]
return f(h, FoldRightStrings(t, z, f))
} else if len(as) == 1 { //Slice has a head and an empty tail.
h := as[0]
return f(h, FoldRightStrings([]string{}, z, f))
}
return z
}
func FilterStrings(as []string, p func(string) bool) []string {
var g = func(h string, accum []string) []string {
if p(h) {
return append(accum, h)
} else {
return accum
}
}
return FoldRightStrings(as, []string{}, g)
}
func AppendStrings(as1, as2 []string) []string {
var g = func(h string, accum []string) []string {
return append(accum, h)
}
return FoldRightStrings(as1, as2, g)
}
func TestAppendStringArrays(t *testing.T) {
strings := []string{"a","b","c"}
bigarray := AppendStrings(AppendStrings(strings, strings),AppendStrings(strings, strings))
if diff := deep.Equal(bigarray, []string{"a","b","c","c","b","a","a","b","c","c","b","a"}); diff != nil {
t.Error(diff)
}
}

Receiving any array type in function arguments

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?
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.
1. Using the []interface{} type
Your function declaration will look something like this.
func chunks(a []interface{}, size int) [][]interface{}
Using this approach will imply some type assertion.
2. Using the reflect package
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.
3. Using some unsafe.Pointer magic.
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)
}
}
4. Try using go generate in your building phase
You can find more information on how to generate go code base on what types you provide.
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)
Run it on the playground.

Create function which performers different operations depending on the input slice argument

I just started to learn Go language and I want to build a function which will be selecting a random subsequence from a slice. However, I don't know what type of values this slice can store, these can be integers, strings or elements of some struct. For example, let's assume I have to structures:
type person struct {
name string
age int
}
type animal struct {
name string
age int
breed string
}
Now, I want to build function getRandomSequence as follows: given as arguments a slice S and a length l the function returns a slice which contains l randomly selected elements from slice S. The problem which I encountered was - how to make this function work for any possible slice. I tried to do the following:
func GetRandomSequence(S interface{}, l int) []interface{} {
switch S.(type) {
case person:
// Do random selection of l elements from S and return them
case animal:
// Do random selection of l elements from S and return them
case int:
// Do random selection of l elements from S and return them
}
return " Not Recognised"
}
Can someone suggest how I can write such function? I manage to make similar (i.e., general) functions work if S would be a single element of any type (so instead of []interface{} would be just interface{}) but I cannot find out how to solve this problem.
Just use interface{} not []interface{}. An empty interface can store any type, including slices.
Your code would look something like this (although I didn't test):
func GetRandomSequence(S interface{}, l int) interface{} {
returnSlice := []interface{}
switch v := s.(type) {
// inside the switch v has the value of S converted to the type
case []person:
// v is a slice of persons here
case []animal:
// v is a slice of animals here
case []int:
// v is a slice of ints here
case default:
// v is of type interface{} because i didn't match any type on the switch
// I recommend you return nil on error instead of a string
// or always return 2 things, the value and an error like
// the standard library
return "Not Recognized"
}
rerurn returnSlice
}
I recommend you do the complete Tour of go, but for this question the answer is here.
Depending on what you want to do exactly, it looks like you might not need different types of slices but a slice of interface{}. If in your function to extract random elements from the slice you don't care about the type of the elements just do:
func GetRandomSequence(S []interface{}, l int) []interface{} {
returnSlice := make([]interface{}, 0, l)
for i:=0; i<l; i++ {
// S[i] here is always of type interface{}
returnSlice = append(returnSlice, S[getRnd()]) // you need to implement getRnd() or just "math/rand" or something.
}
return returnSlice
}
Write a sample function that works with slice indices.
// Sample k random elements from set of n elements.
// The function set sets an element in the output given
// an index in the output and the index in the input.
func sample(k int, n int, assign func(out int, in int)) {
for i := 0; i < k; i++ {
set(i, i)
}
for i := k; i < n; i++ {
j := rand.Intn(i + 1)
if j < k {
set(j, i)
}
}
}
Use it like this:
in := []person{ {"John", 10}, {"Sally", 11}, {"James", 9}, {"Eve", 8} }
out := make([]person, 2)
sample(len(out), len(in), func(i, j int) { out[i] = in[j] })
Because sample works with length and index values only, it can be used on a slice of any type.
This approach is similar to sort.Search in the standard library.

Initialize array of array of strings in GoLang and Rust

I want to initialize a 2D array in which each member of inner array holds a string of 1000 x's. Something like:
var data = [num_rows][num_cols]string("x....x(upto 1000)")
But all google searches have been futile. In C++ I can achieve similar thing like this:
vector<vector<string>> data(num_rows, vector<string>(num_cols, string("x",1000)));
And in Ruby something like this:
Array.new(num_rows) { Array.new(num_cols) { "x"*1000 } }
Want to achieve similar result in go but I am unable to find any documentation to fill a string and initialize a 2D array. Also note that I want to generate the string for each member of array rather than using an available string.
PS : I am also looking for something similar in Rust
In Rust, it depends on what you want to use these values for. I like this answer for creating the repeated string. The "rows" depend on if you want reference or copy semantics which is made explicit in rust. The borrows vector is a bunch of borrowed strings that refer back to the memory owned by x_s. The copies vector is a bunch of in memory copies of the original x_s string.
use std::iter;
fn main() {
let num_rows = 1000;
let num_cols = 1000;
let x_s : String = iter::repeat('x').take(num_cols).collect();
// pick one of the below
let borrows : Vec<&str> = vec![&*x_s ; num_rows];
let copies : Vec<String> = vec![x_s.clone() ; num_rows];
}
The call to clone in the last line is because the vec macro moves the value sent into it. The vec macro will also clone this clone num_rows times in the case of the copies. Note that this clone is probably not necessary in most use cases as you would not normally have borrows and copies in the same scope at the same time.
As a caveat, I am fairly new to rust but believe this to be a decent answer. I am happy to accept corrections.
you could use slices. this may not be the shortest solution, but it works for me.
package main
import (
"fmt"
"strings"
)
func main() {
xs := strings.Repeat("x", 1000)
num_rows := 5
num_cols := 5
data := make([][]string, num_rows)
for y := 0; y < num_rows; y++ {
data[y] = make([]string, num_cols)
for x := 0; x < num_cols; x++ {
data[y][x] = xs
}
}
fmt.Printf("%T", data)
fmt.Print(data)
}
A very simple on-line exemple in rust :
fn main() {
let data: Vec<String> = (0..1000).map(|n| (0..n).map(|_| 'x').collect()).collect();
println!("{:?}", data);
}

Go: Arrays of arrays, arrays of slices, slices of arrays and slices of slices

Trying to teach myself and finding it hard to find examples, and my brain's in a knot already. Very unsure about 3 and 4 and need help for making 5 work.
package main
import "fmt"
func main () {
println("0. Array:")
var a = [...]int{4,5,6,7,8,9} //assign
fmt.Println(a,"\n")
println("1. Slice:")
var as []int
as = a[:] //assign
fmt.Println(as,"\n")
println("2. Array of arrays:")
var b [4][len(a)]int
for i:= range b { //assign
b[i]=a
}
fmt.Println(b,"\n")
println("3. Array of slices:")
var d [len(b)][]int
for i:= range b { // assign
d[i] = b[i][:] //does this really work?
}
fmt.Println(d,"\n")
println("4. Slice of arrays:")
var c [][len(a)]int
c = b[:][:] // assign, does this really work?
fmt.Println(c,"\n")
println("5. Slice of slices:")
var e [][]int
// e = c // ???
fmt.Println(e,"\n")
}
Part 3 works.
Part 4 contains an unnecessary [:].
println("4. Slice of arrays:")
var c [][len(a)]int
c = b[:] // one [:], not two
fmt.Println(c, "\n")
b[:] is evaluated as a slice where each element is a [len(a)]int. If you add another [:], you are slicing the slice again. Since for any slice s, s[:] == s, it is a no op.
Part 5, you can slice your array of slices.
println("5. Slice of slices:")
var e [][]int
e = d[:]
fmt.Println(e, "\n")
I posted a complete example at http://play.golang.org/p/WDvJXFiAFe.
The answer to "does this really work?" depends on what you are expecting. Consider this example at http://play.golang.org/p/7Z5hKioTI_
package main
import "fmt"
func main() {
fmt.Println("0. Array:")
var a = [...]int{4, 5, 6, 7, 8, 9} //assign
fmt.Println(a, "\n")
fmt.Println("1. Slice:")
var as []int
as = a[:] //assign
fmt.Println(as, "\n")
fmt.Println("new slice:")
ns := make([]int, len(a))
copy(ns, a[:])
fmt.Print(ns, "\n\n")
fmt.Println("modifying array...")
a[0] = 10
fmt.Print("array is now:\n", a, "\n\n")
fmt.Print("slice is now:\n", as, "\n\n")
fmt.Print("new slice is still:\n", ns, "\n")
}
It shows how slices have an underlying array, and that the examples in your OP make slices using the same underlying array. If you want slices to have independent contents, you must make new slices and copy the data. (or there are tricks with append...)
Also as a side note, println sends data to stderr not stdout, and formats some data types differently than fmt.Println. To avoid confusion, it's best to stay in the habit of using fmt.Println.

Resources