looping with range in Go - loops

Correct me if I'm wrong, there are only 3 types of loops in Go.
Type1 (The most basic type, with a single condition):
for i <= 3 {...}
Type2 (Classical for-loop)
for j := 7; j <= 9; j++ {...}
Type3 (infinite loop rely on break)
for {...break}
Then I come across this for loop that sums the value from array
nums := []int{2, 3, 4}
sum := 0
for _, num := range nums {
sum += num
}
fmt.Println("sum:", sum)//"sum: 9"
Is the above for-loop to be considered Type1 where it automatically applies <= and range of nums as max value? Can I in any way change the value? maybe I need two extra loops? Can we apply something like range + 2?

From Effective Go:
The Go for loop is similar to—but not the same as—C's. It unifies for and while and there is no do-while. There are three forms, only one of which has semicolons.
// Like a C for
for init; condition; post { }
// Like a C while
for condition { }
// Like a C for(;;)
for { }
It continues:
If you're looping over an array, slice, string, or map, or reading from a channel, a range clause can manage the loop.
for key, value := range oldMap {
newMap[key] = value
}
From this I think of range loops as a for condition { } loop, where the condition (such as it is) is that the variables being designated as the values of the array/slice/string/map/chan are not nil, though in practice even explicitly nil values work
for _, v := range []interface{}{nil, nil, nil, nil} {
// will still iterate four times
}
In reality it might be more useful to think of Go's for loop as a contextual combination of a C-style for init; condition; post loop, a classical while loop, and a more modern foreach loop.

Type1 will work almost like while in other languages. Since there is no while in go language it uses for in that case.
Type2 is the classic for loop like in other languages as you have also stated.
Type3 is used to range over various data structures like arrays, slice, maps
range on arrays and slices provides both the index and value for each
entry like the example you have given
nums := []int{2, 3, 4}
sum := 0
for _, num := range nums {
sum += num
}
fmt.Println("sum:", sum)//"sum: 9"
range on map iterates over key/value pairs.
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
fmt.Printf("%s -> %s\n", k, v)
}
range on strings iterates over Unicode code points. The first value is
the starting byte index of the rune and the second the rune itself.
for i, c := range "go" {
fmt.Println(i, c)
}
For more information, Check Go by example website for usage of range

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)
}
}

Aliasing of slices

How to check whether two slices are backed up by the same array?
For example:
a := []int{1, 2, 3}
b := a[0:1]
c := a[2:3]
alias(b, c) == true
How should alias look like?
In general you can't tell if the backing array is shared between 2 slices, because using a full slice expression, one might control the capacity of the resulting slice, and then there will be no overlap even when checking the capacity.
As an example, if you have a backing array with 10 elements, a slice may be created that only contains the first 2 elements, and its capacity might be 2. And another slice may be create that only holds its last 2 elements, its capacity again being 2.
See this example:
a := [10]int{}
x := a[0:2:2]
y := a[8:10:10]
fmt.Println("len(x) = ", len(x), ", cap(x) = ", cap(x))
fmt.Println("len(y) = ", len(y), ", cap(y) = ", cap(y))
The above will print that both lengths and capcities of x and y are 2. They obviously have the same backing array, but you won't have any means to tell that.
Edit: I've misunderstood the question, and the following describes how to tell if (elements of) 2 slices overlap.
There is no language support for this, but since slices have a contiguous section of some backing array, we can check if the address range of their elements overlap.
Unfortunately pointers are not ordered in the sense that we can't apply the < and > operators on them (there are pointers in Go, but there is no pointer arithmetic). And checking if all the addresses of the elements of the first slice matches any from the second, that's not feasible.
But we can obtain a pointer value (an address) as a type of uintptr using the reflect package, more specifically the Value.Pointer() method (or we could also do that using package unsafe, but reflect is "safer"), and uintptr values are integers, they are ordered, so we can compare them.
So what we can do is obtain the addresses of the first and last elements of the slices, and by comparing them, we can tell if they overlap.
Here's a simple implementation:
func overlap(a, b []int) bool {
if len(a) == 0 || len(b) == 0 {
return false
}
amin := reflect.ValueOf(&a[0]).Pointer()
amax := reflect.ValueOf(&a[len(a)-1]).Pointer()
bmin := reflect.ValueOf(&b[0]).Pointer()
bmax := reflect.ValueOf(&b[len(b)-1]).Pointer()
return !(amax < bmin || amin > bmax)
}
Testing it:
a := []int{0, 1, 2, 3}
b := a[0:2]
c := a[2:4]
d := a[0:3]
fmt.Println(overlap(a, b)) // true
fmt.Println(overlap(b, c)) // false
fmt.Println(overlap(c, d)) // true
Try it on the Go Playground.
Found one way of this here. The idea is that while I don't think there's a way of finding the beginning of the backing array, ptr + cap of a slice should[*] point to the end of it. So then one compares the last pointer for equality, like:
func alias(x, y nat) bool {
return cap(x) > 0 && cap(y) > 0 && &x[0:cap(x)][cap(x)-1] == &y[0:cap(y)][cap(y)-1]
}
[*] The code includes the following note:
Note: alias assumes that the capacity of underlying arrays is never changed for nat values; i.e. that there are no 3-operand slice expressions in this code (or worse, reflect-based operations to the same effect).

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.

Go: range and len of multidimensional array?

Is it possible to use range and len on a multidimensional array?
Either with var a [3]int8 or
package main
func main () {
var a [3][5]int8
for h := range a {
println(h)
}
println(len(a))
}
Both produce
0
1
2
3
?
Thanks to dystroy's answer, here's an example of writing and reading a 3-dimensional array i was able to adapt (posting here because I had much trouble finding any examples of this, so maybe this will help someone else):
package main
func main() {
var a [3][5][7]uint8
//write values to array
for x, b := range a {
for y, c := range b {
for z, _ := range c {
a[x][y][z] = uint8(x*100+y*10+z)
}
}
}
//read values from array
for _, h := range a {
for _, i := range h {
for _, j := range i {
print(j, "\t")
}
println()
}
println()
}
}
In Go as in most languages, what you call a multidimensional array is an array of arrays. The len operator only gives you the length of the "external" array.
Maybe the var declaration could be clearer for you if you see it as
var a [3]([5]int8)
which also compiles. It's an array of size 3 whose elements are arrays of size 5 of int8.
package main
import "fmt"
func main() {
var a [3][5]int8
for _, h := range a {
fmt.Println(len(h)) // each one prints 5
}
fmt.Println(len(a)) // prints 3, the length of the external array
}
outputs
5
5
5
3
To loop safely through the whole matrix, you can do this :
for _, h := range a {
for _, cell := range h {
fmt.Print(cell, " ")
}
fmt.Println()
}
If you need to change the content, you may do
for i, cell := range h { // i is the index, cell the value
h[i] = 2 * cell
}
The solution with range is already provided so i'll talk about how to use length (len) to go through a multi-dimesional array in golang.
So if u have an array arr[][] :
[1,2,3]
[4,5,6]
Now the len(arr) will output = 2.
while len(arr[1]) will output = 3.
Sample code is provided here : https://play.golang.org/p/XerzPhkQrhU
No, the first one produces 0,1,2 ( index of in the range )
http://play.golang.org/p/0KrzTRWzKO
And the second one produces 3 ( the length of the array ).
http://play.golang.org/p/0esKFqQZL0
In both cases you're using the outermost array.

Dynamically initialize array size in go

I try to write a small application in go that takes 'x' numbers of integers from standard input, calculates the mean and gives it back. I have only gotten so far:
func main() {
var elems, mean int
sum := 0
fmt.Print("Number of elements? ")
fmt.Scan(&elems)
var array = new([elems]int)
for i := 0; i < elems; i++ {
fmt.Printf("%d . Number? ", i+1)
fmt.Scan(&array[i])
sum += array[i];
}............
When trying to compile this I get the following error message:
invalid array bound elems
What is wrong here?
You should use a slice instead of an array:
//var array = new([elems]int) - no, arrays are not dynamic
var slice = make([]int,elems) // or slice := make([]int, elems)
See "go slices usage and internals". Also you may want to consider using range for your loop:
// for i := 0; i < elems; i++ { - correct but less idiomatic
for i, v := range slice {
In my opinion, this results from confusion over the usage of the new and make functions. This is a known issue/feature in the Go language, as evidenced by several discussions about new vs make at golang-nuts.
The difference between new and make may become clearer by letting Go print out the type of the value created by new and make:
package main
import "fmt"
func main() {
fmt.Printf("%T %v\n", new([10]int), new([10]int))
fmt.Printf("%T %v\n", make([]int, 10), make([]int, 10))
}
The output:
*[10]int &[0 0 0 0 0 0 0 0 0 0]
[]int [0 0 0 0 0 0 0 0 0 0]
As can be seen from the type, to access an array element of new([10]int) we would first need to dereference the pointer.
Both new and make require a Go type as their 1st argument. However, the expression [elems]int is not a Go type (unless elems is a Go constant, which isn't the case here).
For further reference, see http://golang.org/doc/go_spec.html#Allocation and http://golang.org/doc/go_spec.html#The_zero_value.
To get a better understanding of whether the result of new is usable, it may be helpful to lookup whether len and cap work with zero (nil) values: http://golang.org/doc/go_spec.html#Length_and_capacity
See The Go Programming Language Specification
http://golang.org/ref/spec#Array_types
http://golang.org/ref/spec#Constants
It says:"The length is part of the array's type; it must evaluate to a non- negative constant representable by a value of type int. "
Constants by no means vary.

Resources