Why is ID after the assignment in the loop 0? - go

I am trying to create a array of struct and initiate some data in it.
The struct:
type Person struct{
id int
enlighten bool
channel chan int
}
The assignments:
table := make([]Philospher, numPhil)
for i :=0; i < 5; i++{
p := Philospher{
id: i,
enlighten: false,
channel: make(chan int),
}
table = append(table, p)
}
for j :=0; j < 5; j++{
fmt.Println(table[j].id);
}
The following are the output of above code:
0
0
0
0
0
I am trying to figure out why it is not
0
1
2
3
4
I have also tried to use add & in front of Philospher, and it is the same thing
Any help is appreciated

Your make call is creating a Philosopher slice with the initial length of 5. From the spec:
A new, initialized slice value for a given element type T is made using the built-in function make, which takes a slice type and parameters specifying the length and optionally the capacity. A slice created with make always allocates a new, hidden array to which the returned slice value refers. That is, executing
make([]T, length, capacity)
Those first 5 Philosophers are the zero value of Philosopher. You append 5 more Philosophers to the end of the slice which gives it a final length of 10. What I believe you meant to do is create a slice with the length of 0 but a capacity of 5:
table := make([]Philosopher, 0, numPhil)
https://play.golang.org/p/a5QP6wd6Rs_9

Because of this:
table := make([]Philospher, numPhil)
This creates table with numPhil empty elements. Then you add your Philosohpers to the end of this empty table, and print of the first 5. Apparently, numPhil >= 5, so it prints out the first empty ones.
Change the initialization to:
table:= make([]Philosopher,0,numPhil)
to reserve space for numPhil elements, with a size of 0.

Related

How to append to a 2d slice

I have data that is created rows by rows, 6 columns, I don't know the final number of rows in advance.
Currently i'm creating a 2D slice of 200x6 with all zeros and then i replace these zeros gradually with my data, row by row. The data comes from another dataframe df
It works but i don't like to end up with the last rows of my slice full of zeros. I see 2 solutions:
- I delete all the last rows with only zeros when I'm done
- I create an empty slice and append my data progressively to it
I tried various things but could not figure out how to code any of these 2 solutions.
Currently my code looks like this:
var orders [200][6]float64 // create my 2d slice with zeros
order_line := 0
for i := start_line; i <= end_line; i++ {
if sell_signal == "1" {
//record line number and sold price in orders slice
orders[order_line][1] = float64(i+1)
orders[order_line][2],err = strconv.ParseFloat(df[i][11], 64)
order_line = order_line + 1
}
}
I looked at the Append command, but I tried all sorts of combinations to make it work on a 2d slice, could not find one that works.
edit: from the comments below I understand that i'm actually creating an array, not a slice, and there is no way to append data to an array.
In Golang slices are preferred in place of arrays.
Creating so many rows in prior is not required, just create a slice every time you are looping over your data to add a new row in the parent slice. That will help you to have only required number of rows and you need to worry about the length Since you are appending a slice at an index of parent slice.
package main
import (
"fmt"
"math/rand"
)
func main() {
orders := make([][]float64, 0) // create my 2d slice with zeros
for i := 0; i <= 6; i++ {
value := rand.Float64()
temp := make([]float64, 0)
temp = append(temp, value)
orders = append(orders, [][]float64{temp}...)
}
fmt.Println(orders)
}
Please check working code on Playground
If you notice I am creating a new temp slice in loop which contains the float64 value and then appending value to the temp slice which I have passed to the parent slice.
So everytime I append the temp slice to the parent slice a new row will be created.
Note:
Arrays have their place, but they're a bit inflexible, so you don't
see them too often in Go code. Slices, though, are everywhere. They
build on arrays to provide great power and convenience.
Edited:
To work on first 3 columns and then manipulate the values for next 3 columns which will be added to the temp slice and appended to the main slice. Use below code logic:
package main
import (
"fmt"
"math/rand"
"strconv"
)
func main() {
orders := make([][]float64, 0) // create my 2d slice with zeros
for i := 0; i <= 6; i++ {
value := rand.Float64()
// logic to create first 3 columns
temp := make([]float64, 0)
temp = append(temp, value)
temp2 := make([]float64, 3)
// logic to create next 3 columns on basis of previous 3 columns
for j, value := range temp {
addcounter, _ := strconv.ParseFloat("1", 64)
temp2[j] = value + addcounter
}
temp = append(temp, temp2...)
orders = append(orders, [][]float64{temp}...)
}
fmt.Println(orders)
}
Working Example
Given that the outer container has an unknown number of elements and the inner container has exactly six elements, use a slice of arrays.
var orders [][6]float64
for i := start_line; i <= end_line; i++ {
if sell_signal == "1" {
n, err = strconv.ParseFloat(df[i][11], 64)
if err != nil {
// handle error
}
orders = append(orders, [6]float64{1: float64(i + 1), 2: n})
}
}
This code uses a composite literal [6]float64 value instead of assigning element by element as in the question.
You can come back and access elements of the [6]float64 at a later time. For example:
orders[i][3] = orders[i][1] + orders[i][2]
For better readability, and easier slice handling, just create a struct type and fill a slice with them. This allows you to properly name each field instead of magic index numbers and makes it easier to fill in the rows as well as utilize later. Unless there is some specific reason to use arrays/slices for the columns, this is more idiomatic Go. The following example would fill a slice with however many results you have, and no more.
Full example here: https://play.golang.org/p/mLtabqO8MNj
type Row struct {
Thing float64
Data float64
More float64
Stuff float64
Another float64
Number float64
}
var rows []*Row
numResults := 15
for i := 0; i <= numResults; i++ {
row := &Row{}
row.Thing = 2.5
// ... fill values
rows = append(rows, row)
}

How to assign a value to the empty slice after the declaration

I am trying to assign a value to the empty slice as follows.
func main() {
var s []int
fmt.Println(s, len(s), cap(s))
s[0] = 99
}
And it throws an exception,
panic: runtime error: index out of range
Note:
I know one way of doing this by initializing the value at declaration part as follows. But in the above example I am trying to assign a value after the declaration.
var s []int{99}
Is there a way to achieve this?
Empty slices cannot just be assigned to. Your print statement shows that the slice has length and capacity of 0. Indexing at [0] is definitely out of bounds.
You have (at least) three choices:
Append to the slice: s = append(s, 99)
or Initialize the slice to be non-empty: s := make([]int, 1)
or Initialize your slice with the element you want: s := []int{99}
You can find tutorials on slices in the Go tour, or a lot more details about slice usage and internals.
var s []int{99}
The above works but if you want to assign after declaration, then you would need to create a slice using make function with enough length
s := make([]int, 10)
s[0] = 10
fmt.Println(s)
This will initialize slice and set the length to 10 and its elements to zero values
Note: doing s[10] or any greater index will panic since the slice is initialised with length 10. If you want to dynamically increase the slice size, then use append
You can do that by using append function.
func main() {
var s []int
s = append(s,99)
fmt.Println(s) // [99]
}
https://play.golang.org/p/XATvSo2OB6f
// slice declaration; no memory allocation
var slice []int
//slice initialization with length (0) and capacity (10);
//memory allocated for 10 ints
slice = make([]int, 0, 10)
// push to the slice value - than increase length
slice = append(slice, 1)
//change the value. Index has to be lower then length of slice
slice[0] = 2
Take a loot at this output - https://play.golang.com/p/U426b1I5zRq
Of course, you can skip initialization with make, append will do it for you with default value of capacity (2). But for performance it is better to allocate memory only once (if you know how many elements are going to be added to the slice)

What is the mechanism of using append to prepend in Go?

Suppose I have a slice slice of type int. While declaring, I set the third argument to size, which I believe reserves memory for at least size ints by setting the cap parameter of the slice.
slice:=make([]int,0,size)
Now, suppose I have an integer variable value. To add it to the slice at the end, I use
slice=append(slice,value)
If the number of elements currently in the slice is less than size, then there will be no need to copy the entire underlying array to a new location in order to add the new element.
Further, if I want to prepend value to slice, as suggested here and here, I use
slice=append([]int{value},slice...)
My question is, what happens in this case? If the number of elements is still less than size, how are the elements stored in the memory? Assuming a contiguous allocation when the make() function was invoked, are all existing elements right shifted to free the first space for value? Or is memory reallocated and all elements copied?
The reason for asking is that I would like my program to be as fast as possible, and would like to know if this is a possible cause for slowing it down. If it is so, is there any alternative way of prepending that would be more time efficient?
With reslicing and copying
The builtin append() always appends elements to a slice. You cannot use it (alone) to prepend elements.
Having said that, if you have a slice capacity bigger than length (has "free" space after its elements) to which you want to prepend an element, you may reslice the original slice, copy all elements to an index one higher to make room for the new element, then set the element to the 0th index. This will require no new allocation. This is how it could look like:
func prepend(dest []int, value int) []int {
if cap(dest) > len(dest) {
dest = dest[:len(dest)+1]
copy(dest[1:], dest)
dest[0] = value
return dest
}
// No room, new slice need to be allocated:
// Use some extra space for future:
res := make([]int, len(dest)+1, len(dest)+5)
res[0] = value
copy(res[1:], dest)
return res
}
Testing it:
s := make([]int, 0, 5)
s = append(s, 1, 2, 3, 4)
fmt.Println(s)
s = prepend(s, 9)
fmt.Println(s)
s = prepend(s, 8)
fmt.Println(s)
Output (try it on the Go Playground):
[1 2 3 4]
[9 1 2 3 4]
[8 9 1 2 3 4]
Note: if no room for the new element, since performance does matter now, we didn't just do:
res := append([]int{value}, dest...)
Because it does more allocations and copying than needed: allocates a slice for the literal ([]int{value}), then append() allocates a new when appending dest to it.
Instead our solution allocates just one new array (by make(), even reserving some space for future growth), then just set value as the first element and copy dest (the previous elements).
With linked list
If you need to prepend many times, a normal slice may not be the right choice. A faster alternative would be to use a linked list, to which prepending an element requires no allocations of slices / arrays and copying, you just create a new node element, and you designate it to be the root by pointing it to the old root (first element).
The standard library provides a general implementation in the container/list package.
With manually managing a larger backing array
Sticking to normal slices and arrays, there is another solution.
If you're willing to manage a larger backing array (or slice) yourself, you can do so by leaving free space before the slice you use. When prepending, you can create a new slice value from the backing larger array or slice which starts at an index that leaves room for 1 element to be prepended.
Without completeness, just for demonstration:
var backing = make([]int, 15) // 15 elements
var start int
func prepend(dest []int, value int) []int {
if start == 0 {
// No more room for new value, must allocate bigger backing array:
newbacking := make([]int, len(backing)+5)
start = 5
copy(newbacking[5:], backing)
backing = newbacking
}
start--
dest = backing[start : start+len(dest)+1]
dest[0] = value
return dest
}
Testing / using it:
start = 5
s := backing[start:start] // empty slice, starting at idx=5
s = append(s, 1, 2, 3, 4)
fmt.Println(s)
s = prepend(s, 9)
fmt.Println(s)
s = prepend(s, 8)
fmt.Println(s)
// Prepend more to test reallocation:
for i := 10; i < 15; i++ {
s = prepend(s, i)
}
fmt.Println(s)
Output (try it on the Go Playground):
[1 2 3 4]
[9 1 2 3 4]
[8 9 1 2 3 4]
[14 13 12 11 10 8 9 1 2 3 4]
Analysis: this solution makes no allocations and no copying when there is room in the backing slice to prepend the value! All that happens is it creates a new slice from the backing slice that covers the destination +1 space for the value to be prepended, sets it and returns this slice value. You can't really get better than this.
If there is no room, then it allocates a larger backing slice, copies over the content of the old, and then does the "normal" prepending.
With tricky slice usage
Idea: imagine that you always store elements in a slice in backward order.
Storing your elements in backward order in a slice means a prepand becomes append!
So to "prepand" an element, you can simply use append(s, value). And that's all.
Yes, this has its limited uses (e.g. append to a slice stored in reverse order has the same issues and complexity as a "normal" slice and prepand operation), and you lose many conveniences (ability to list elements using for range just to name one), but performance wise nothing beats prepanding a value just by using append().
Note: iterating over the elements that stores elements in backward order has to use a downward loop, e.g.:
for i := len(s) - 1; i >= 0; i-- {
// do something with s[i]
}
Final note: all these solutions can easily be extended to prepend a slice instead of just a value. Generally the additional space when reslicing is not +1 but +len(values), and not simply setting dst[0] = value but instead a call to copy(dst, values).
The "prepend" call will need to allocate an array and copy all elements because a slice in Go is defined as a starting point, a size and an allocation (with the allocation being counted from the starting point).
There is no way a slice can know that the element before the first one can be used to extend the slice.
What will happen with
slice = append([]int{value}, slice...)
is
a new array of a single element value is allocated (probably on stack)
a slice is created to map this element (start=0, size=1, alloc=1)
the append call is done
append sees that there is not enough room to extend the single-element slice so allocates a new array and copies all the elements
a new slice object is created to refer to this array
If appending/removing at both ends of a large container is the common use case for your application then you need a deque container. It is unfortunately unavailable in Go and impossible to write efficiently for generic contained types while maintaining usability (because Go still lacks generics).
You can however implement a deque for your specific case and this is easy (for example if you have a large container with a known upper bound may be a circular buffer is all you need and that is just a couple of lines of code away).
I'm very new to Go, so may be the following is very bad Go code... but it's an attempt to implement a deque using a growing circular buffer (depending on the use case this may be or may be not a good solution)
type Deque struct {
buffer []interface{}
f, b, n int
}
func (d *Deque) resize() {
new_buffer := make([]interface{}, 2*(1+d.n))
j := d.f
for i := 0; i < d.n; i++ {
new_buffer[i] = d.buffer[j]
d.buffer[j] = nil
j++
if j == len(d.buffer) {
j = 0
}
}
d.f = 0
d.b = d.n
d.buffer = new_buffer
}
func (d *Deque) push_back(x interface{}) {
if d.n == len(d.buffer) {
d.resize()
}
d.buffer[d.b] = x
d.b++
if d.b == len(d.buffer) {
d.b = 0
}
d.n++
}
func (d *Deque) push_front(x interface{}) {
if d.n == len(d.buffer) {
d.resize()
}
if d.f == 0 {
d.f = len(d.buffer)
}
d.f--
d.buffer[d.f] = x
d.n++
}
func (d *Deque) pop_back() interface{} {
if d.n == 0 {
panic("Cannot pop from an empty deque")
}
if d.b == 0 {
d.b = len(d.buffer)
}
d.b--
x := d.buffer[d.b]
d.buffer[d.b] = nil
d.n--
return x
}
func (d *Deque) pop_front() interface{} {
if d.n == 0 {
panic("Cannot pop from an empty deque")
}
x := d.buffer[d.f]
d.buffer[d.f] = nil
d.f++
if d.f == len(d.buffer) {
d.f = 0
}
d.n--
return x
}

Standard library Priority Queue push method

The code snippet below is the library implementation of the push methods for a priority queue. I am wondering why the line with the code a = a[0 : n+1] does not throw an out of bounds errors.
func (pq *PriorityQueue) Push(x interface{}) {
// Push and Pop use pointer receivers because they modify the slice's length,
// not just its contents.
// To simplify indexing expressions in these methods, we save a copy of the
// slice object. We could instead write (*pq)[i].
a := *pq
n := len(a)
a = a[0 : n+1]
item := x.(*Item)
item.index = n
a[n] = item
*pq = a
}
a slice is not an array; it is a view onto an existing array. The slice in question is backed by an array larger than itself. When you define a slice of an existing slice, you're actually slicing the underlying array, but the indexes referenced are relative to the source slice.
That's a mouthful. Let's prove this in the following way: we'll create a slice of zero length, but we'll force the underlying array to be larger. When creating a slice with make, the third parameter will set the size of the underlying array. The expression make([]int, 0, 2) will allocate an array of size 2, but it evaluates to a size-zero slice.
package main
import ("fmt")
func main() {
// create a zero-width slice over an initial array of size 2
a := make([]int, 0, 2)
fmt.Println(a)
// expand the slice. Since we're not beyond the size of the initial
// array, this isn't out of bounds.
a = a[0:len(a)+1]
a[0] = 1
fmt.Println(a)
fmt.Println(a[0:len(a)+1])
}
see here. You can use the cap keyword to reference the size of the array that backs a given slice.
The specific code that you asked about loops over cap(pq) in the calling context (container/heap/example_test.go line 90). If you modify the code at the call site and attempt to push another item into the queue, it will panic like you expect. I ... probably wouldn't suggest writing code like this. Although the code in the standard library executes, I would be very sour if I found that in my codebase. It's generally safer to use the append keyword.
Because it works in a specific example program. Here are the important parts from the original/full example source)
const nItem = 10
and
pq := make(PriorityQueue, 0, nItem)
and
for i := 0; i < cap(pq); i++ {
item := &Item{
value: values[i],
priority: priorities[i],
}
heap.Push(&pq, item)
}
Is it an example from container/heap? If yes, then it doesn't throws an exception because capacity is big enough (see how the Push method is used). If you change the example to Push more items then the capacity, then it'll throw.
It does in general; it doesn't in the container/heap example. Here's the general fix I already gave you some time ago.
func (pq *PriorityQueue) Push(x interface{}) {
a := *pq
n := len(a)
item := x.(*Item)
item.index = n
a = append(a, item)
*pq = a
}
Golang solution to Project Euler problem #81

Slice index greater than length and less than capacity gives error

Following code gives a error at runtime.
package main
import fmt "fmt"
func main(){
type b []int
var k = make([]b, 5, 10)
fmt.Printf("%d\n",k[8])
fmt.Printf("%d", len(k))
}
Error is as follows.
panic: runtime error: index out of range
runtime.panic+0x9e /go/src/pkg/runtime/proc.c:1060
runtime.panic(0x453b00, 0x300203f0)
runtime.panicstring+0x94 /go/src/pkg/runtime/runtime.c:116
runtime.panicstring(0x4af6c6, 0xc)
runtime.panicindex+0x26 /go/src/pkg/runtime/runtime.c:73
runtime.panicindex()
main.main+0x8d C:/GOEXCE~1/basics/DATATY~1/slice.go:9
main.main()
runtime.mainstart+0xf 386/asm.s:93
runtime.mainstart()
runtime.goexit /go/src/pkg/runtime/proc.c:178
runtime.goexit()
----- goroutine created by -----
_rt0_386+0xbf 386/asm.s:80
While if k[0] or k[1] is printed, it runs fine. Can you please explain what exactly capacity means for slices.
You are simply indexing, so the index must be less than the length. The relevant section of the Go specification says that
A primary expression of the form
a[x]
...
For a of type A or *A where A is an array type, or for a of type S
where S is a slice type:
x must be an integer value and 0 <= x < len(a)
However, if you were "slicing" (e.g. a[6:9]), then it would work with indexes that are greater than the length but within the capacity.
Read the Go Programming Language Specification.
Length and capacity
The capacity of a slice is the number of elements for which there is
space allocated in the underlying array. At any time the following
relationship holds:
0 <= len(s) <= cap(s)
var slice = make([]b, 5, 10)
is equal to
var array [10]b
slice := array[:5]
The difference is that when you use var slice = make([]b, 5, 10), you can't access the array under slice. The slice := array[:5] means the first element of slice is array[0] and the length of slice is 5, which means slice[0] == array[0], slice[1] == array[1], ... slice[4] == array[4]. Because you can only access the index that is less than the length(which means 0 <= index < length). The length of slice is 5 and the length of array is 10, so you can access array[8](0<=8<10) but can't access slice[8](8>5).
Full sample:
package main
import fmt "fmt"
func main(){
type b []int
var array [10]b
slice := array[:5]
// []
fmt.Printf("%d\n",slice[1])
// []
fmt.Printf("%d\n",array[8])
// panic: runtime error: index out of range
fmt.Printf("%d\n",slice[8])
}
Reference
https://blog.golang.org/go-slices-usage-and-internals

Resources