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)
}
}
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.
This question already has answers here:
How to search for an element in a golang slice
(8 answers)
Closed 7 months ago.
Suppose there is an slice having integers in it. And we have declared a variable which contains a integer value then I have to find the value from that slice without using for loop.
Using for loop I do like this:-
package main
import (
"fmt"
)
func main() {
value := 10
var interf []interface{}
for i := 1; i <= value; i++{
interf = append(interf, i)
}
fmt.Println(interf)
for _,v := range interf{
if value == v{
fmt.Println("Matched")
}
}
}
How we do this same thing without using for loop
Without a for loop, no* (see How to search for an element in a golang slice).
* Actually you could do it without a for loop using a recursive function. See solution at the end of the answer.
There is no ready function for this in the standard library, but this is how easy it is to create one yourself:
func find(what interface{}, where []interface{}) (idx int) {
for i, v := range where {
if v == what {
return i
}
}
return -1
}
And using it:
what := 10
where := []interface{}{1, 2, 3, 10, 5}
fmt.Println(find(what, where))
Output (try it on the Go Playground):
3
Also note that it would be faster and more convenient to use []int slice type instead of []interface{}:
func find(what int, where []int) (idx int) {
for i, v := range where {
if v == what {
return i
}
}
return -1
}
And then using it:
what := 10
where := []int{1, 2, 3, 10, 5}
fmt.Println(find(what, where))
Output is the same. Try this one on the Go Playground.
You could create a function that accepts slices of any type using the interface{} type, but that would require reflection to implement it, which would be slower and not worthy to be used. Instead just create a function with concrete slice types if you need, or just use the for loop in place.
For completeness, here's the solution that uses no for loops but a recursive function. This is here only for educational purposes, the solutions above are superior to this:
func find(what int, where []int) (idx int) {
if len(where) == 0 {
return -1
}
if what == where[0] {
return 0
}
if idx = find(what, where[1:]); idx < 0 {
return -1 // Not found in the rest of the slice
}
return 1 + idx
}
Try this one on the Go Playground.
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.
I have two one dimensional array and I want to combine the two single arrays into one multi dimensional array with append.
How would this be done for the fastest in go?
val time []int64
val value []float64
val 2darray [][]int64, float64
Would append be the best way to do this in go?
Here's an example of how it can be done:
package main
import (
"fmt"
)
type TimeAndValue struct {
time int64
value float64
}
func main() {
times := []int64{0, 1, 2, 3, 4}
values := []float64{1.23, 2.34, 3.45, 4.56, 5.67}
timesAndValues := zip(times, values)
fmt.Println(timesAndValues)
}
func zip(ts []int64, vs []float64) []TimeAndValue {
if len(ts) != len(vs) {
panic("not same length")
}
var res []TimeAndValue
for i, t := range ts {
res = append(res, TimeAndValue{time: t, value: vs[i]})
}
return res
}
https://play.golang.org/p/1OWJ1HG1XL