Arrays without fixed length in golang [duplicate] - go

This question already has answers here:
Dynamically initialize array size in go
(3 answers)
Closed 2 years ago.
I have recently started with golang and was working with arrays and came across a situation where I did not have the number of elements. Is there a way to initialize a array without a size and then append elements in the end? Something like there in other programming languages like c++, javascript where there are vectors and arrays that can be used and we can add elements by functions like push_back or push. Is there a way that we can do this or is there a library in which we can do this? Thank you!

a := []int{}
a = append(a, 4)
fmt.Println(a)

You can use slice for your purpose.
array := make([]int, 0)
array = append(array, 1)
array = append(array, 2)
Here, array is a slice of int type data and initially of size 0. You can append int type data by append(array, <int-type-data>).

With Golang, Arrays always have a fixed length:
In Go, an array is a numbered sequence of elements of a specific length.
(Source: https://gobyexample.com/arrays)
If you want the flexibility of a variable length, you'll probably want to use a Slice instead:
Slices are a key data type in Go, giving a more powerful interface to sequences than arrays.
(Source: https://gobyexample.com/slices)
This post on the go blog (though old) has a nice overview of the two data types.

Related

for loop value semantic in golang

First question about Go in SO. The code below shows, n has the same address in each iteration. I am aware that such a for loop is called value semantic by some people and what's actually ranged over is a copy of the slice not the actual slice itself. Why does n in each iteration has the same address? Is it because each element in the slice is copied rather than the whole slice is copied once beforehand. If only each element from the original slice is copied, then a single memory address can be reused in each iteration?
package main
import (
"fmt"
)
func main() {
numbers := []int{1, 2}
for i, n := range numbers {
fmt.Println(&n, &numbers[i])
}
}
A sample result from go playground:
0xc000122030 0xc000122020
0xc000122030 0xc000122028
You are slightly wrong in your question, it is not a copy of the slice that is being iterated over. In Go when you pass a slice you really pass a pointer to memory and the size and capacity of that memory, this is called a slice header. The header is copied, but the copy points to the same underlying memory, meaning that when you pass a []int to a function, change the values in that function, the values will be changed in the original []int in the outer code as well.
This is in contrast to an array like [5]int which is passed by value, meaninig this would really be copied when you pass it around. In Go structs, strings, numbers and arrays are passed by value. Slices are really also passed by value but as described above, the value in this case contains a pointer to memory. Passing a copy of a pointer still lets you change the memory pointed to.
Now to your experiment:
for i, n := range numbers
will create two variables before the loop starts: integers i and n. In each loop iteration i will be incremented by 1 and n will be assigned the value (a copy of the integer value that is) of numbers[i].
This means there really are only two variables i and n. They are the same which is what you see in your output.
The addresses of numbers[i] are different of course, they are the memory addresses of the items in the array.
The Go Wiki has a Common Mistakes page talking about this exact issue. It also provides an explanation of how to avoid this issue in real code. The quick answer is that this is done for efficiency, and has little to do with the slice. n is a single variable / memory location that gets assigned a new value on each iteration.
If you want additional insight into why this happens under the hood, take a look at this post.

What is internal implementation of make(map[type1]type2) in Golang? [duplicate]

This question already has answers here:
Golang map internal implementation - how does it search the map for a key?
(3 answers)
Closed 3 years ago.
Golang is a native programming language. So there is a lot of limitation than dynamic languages (like python and ruby).
When initialize Maps as m := make(Map[string]int), this map m seems to be able to contain infinity many key-values.
But when initialize Maps with maps literal or make with cap, The maps cannot contain infinity many key-values.
Some article said that make without cap allocate a huge amount of memory to this map. But this is not option, because if it was true, there will be a giant memory consumption when initialize single map. But no matter what computer hardware monitoring tools I use, the memory is no difference between before and during my program runs.
func main(){
Hello()
}
func Hello(){
m := make(SizeRecord)
l := 10000000
for i := 0; i < l; i++ {
m[strconv.Itoa(i)] = Size{float64(rand.Intn(100)), float64(rand.Intn(100)), float64(rand.Intn(100))}
}
fmt.Println(m)
}
The program take a while to be executed.
I also read an article Go maps in action, it said (I don't know if I have understood correctly) that make without cap use an alternative implementation to represent map and use an unified interface to access the map as the other maps with limited capacity.
If my understanding is wrong, could any body tell me what correct one is?
If I am correct, why didn't golang implement all maps in this way?
Your understanding of how maps work is incorrect. The spec says:
Blockquote
The initial capacity does not bound its size: maps grow to accommodate the number of items stored in them, with the exception of nil maps. A nil map is equivalent to an empty map except that no elements may be added.
So, the capacity is only a hint and it affects the initial size of the map. The map can grow as needed. There is no separate implementation for maps with a given capacity.

Passing a fixed length array to a function

I want to write a function that can accept arrays of fixed length, but different arrays have different lengths.
I know that i can pass the slice with arr[:] (the function will accept []T), but is there another way, maybe more efficient?
I'm using a struct that i'd like to mantain with fixed length arrays (for documentation purposes), so using slices everywhere at declaration time is not optimal for my purpose.
No there is no way to pass different size arrays, because the length of an array is part of the type.
For example [3]int is a different type then [2]int.
At all in Go it is not recommended to use arrays you should use slices (https://golang.org/doc/effective_go.html#arrays).

Stream<double[]> vs DoubleStream

I have to convert double value array into stream
What is difference between following two approach? Which one is better ?
double [] dArray = {1.2,2.3,3.4,4.5};
Stream<double[]> usingStream = Stream.of(dArray); //approach 1
DoubleStream usingArrays = Arrays.stream(dArray); //approach 2
Obviously, Stream.of(dArray) gives you a Stream<double[]> whose single element is the input array, which is probably not what you want. You could use that approach if your input was a Double[] instead of a primitive array, since then you would have gotten a Stream<Double> of the elements of the array.
Therefore Arrays.stream(dArray) is the way to go when you need to transform an array of doubles to a stream of doubles.
Besides the fact that they are different?
DoubleStream can be thought as Stream<Double> (but as a primitive), while Stream<double[]> is a Stream of arrays.
Stream.of and Arrays.stream are entirely different things for different purposes and hence should not be compared.
Stream.of when passed a single dimensional array as in your example will yield a stream with a single element being the array itself which in majority of the cases is not what you want.
Arrays.stream, well as name suggests operates on arrays, whereas Stream.of is more general.
It would have been better and more entertaining had you asked what’s the difference between DoubleStream.of(dArray) and Arrays.stream(dArray).

Why adding items to map during its iteration produce inconsistent result?

From Go Spec:
If map entries are created during iteration, that entry may be produced during the iteration or may be skipped.
So what I expect from that statement is that the following code should at least print number 1, and how many more numbers which are going to be printed is not predictable and is different each time you run the program:
package main
import (
"fmt"
)
func main() {
test := make(map[int]int)
test[1] = 1
j := 2
for i, v := range test {
fmt.Println(i, v)
test[j] = j
j++
}
return
}
Go playground link
On my own laptop (Go version 1.8) at maximum it prints till 8, in playground (still version 1.8) it prints exactly till 3!
I don't care much about the result from playground since its go is not vanilla but I wonder why on my local it never prints more than 8? even I tried to add more items in each iteration to make the possibility of going over 8 higher but there's no difference.
EDIT: my own explanation based on #Schwern 's answer
when the map is created with make function and without any size parameter only 1 bucket is assigned and in go each bucket has a size of 8 elements, so when the range starts it sees that the map has only 1 bucket and it will iterate at maximum 8 times. If I use a size parameter bigger than 7 like make(map[int]int, 8) two buckets is created and there would be possibility that I get more than 8 iterations over the added items.
This is an issue inherent in the design of most hash tables. Here's a simple explanation hand waving a lot of unnecessary detail.
Under the hood, a hash table is an array. Each key is mapped onto an element in the array using a hash function. For example, "foo" might map to element 8, "bar" might map to element 4, and so on. Some elements are empty.
for k,v := range hash iterates through this array in whatever order they happen to appear. The ordering is unpredictable to avoid a collision attack.
When you add to a hash, it adds to the underlying array. It might even have to allocate a new, larger array. It's unpredictable where that new key will land in the hash's array.
So if you add more pairs while you're iterating through the hash, any pair that gets put into the array before the current index won't be seen; the iteration has already past that point. Anything that gets put after might be seen; the iteration has yet to reach that point, but the array might get reallocated and the pairs possibly rehashed.
but I wonder why on my local it never prints more than 8
Because the underlying array is probably of length 8. Go likely allocates the underlying array in powers of 2 and probably starts at 8. The range hash probably starts by checking the length of the underlying array and will not go further, even if it's grown.
Long story short: don't add keys to a hash while iterating through it.

Resources