How does append grows up capacity with more than one elements? - go

I'm not sure how does append work, there are two case as follow:
case 1:
s := make([]int, 0)
s = append(s, 1)
s = append(s, 2)
s = append(s, 3)
s = append(s, 4)
s = append(s, 5)
fmt.Println(cap(s))
In this case output is 8 and this is make sense.
case 2:
s := make([]int, 0)
s = append(s, 1, 2, 3, 4, 5)
fmt.Println(cap(s))
But this case output is 6
Could anyone explain for me?

if you learn about the vector in C++,
you will know the capacity is Dynamically growing,
When you add elements, you will judge whether the capacity is enough. If not enough, the capacity will be increased(not one by one).
In
Where is the implementation of func append in Go?
we can see
CMPQ BX, DI // compare new length (2) with cap (1)
JHI $1, 225 // jump to grow code if len > cap
in offical website
func Append(slice []int, elements ...int) []int {
n := len(slice)
total := len(slice) + len(elements)
if total > cap(slice) {
// Reallocate. Grow to 1.5 times the new size, so we can still grow.
newSize := total*3/2 + 1
newSlice := make([]int, total, newSize)
copy(newSlice, slice)
slice = newSlice
}
slice = slice[:total]
copy(slice[n:], elements)
return slice
}
func Append(slice []int, items ...int) []int {
for _, item := range items {
slice = Extend(slice, item)
}
return slice
}
func Extend(slice []int, element int) []int {
n := len(slice)
if n == cap(slice) {
// Slice is full; must grow.
// We double its size and add 1, so if the size is zero we still grow.
newSlice := make([]int, len(slice), 2*len(slice)+1)
copy(newSlice, slice)
slice = newSlice
}
slice = slice[0 : n+1]
slice[n] = element
return slice
}
newSize := total*3/2 + 1
so first uses Append: 0->1->2->4->4->8(5x3/2+1)
second uses Extend: 0->1->2->4->4->6(3*2)

Related

Add slice as row dynamically to 2d slice

I'm trying to add the slice sofar to a new row in matrix after each iteration.
func combinations(sofar []int, rest []int, n int, matrix [][]int, count int) {
if n == 0 {
//Next two lines problematic
matrix[count] = append(matrix[count], sofar[0], sofar[1], sofar[2])
count++
fmt.Println(sofar)
} else {
for i := range rest[:len(rest)] {
concat := sofar
concat = append(concat, rest[i])
combinations(concat, rest[i+1:], n-1, matrix, count)
}
}
}
func factorial(x uint) uint {
if x == 0 {
return 1
}
return x * factorial(x-1)
}
Driver program
func triangleNumber() int {
sofar := []int{}
rest := []int{1,2,3,4}
matrixSize := factorial(4)/(factorial(1)*factorial(3))
matrix := make([][]int, matrixSize)
count := 0
fmt.Println(matrixSize)
combinations(sofar, rest, 3, matrix, count)
return 0
}
triangleNumber()
I want matrix to be;
[1 2 3]
[1 2 4]
[1 3 4]
[2 3 4]
But instead it's all going in the first row. Also is there a way I can get rid of count, and just add the slice sofar to the next row?
Actually, there are a couple of things I note with your program:
Append adds to the existing slice at its end (after length), so if you are using append for matrix, you need not allocate a slice of that size (see main in the code below)
After you are adding elements to the matrix, it is simply being dumped in your current program. The combinations function needs to return it back so that when future elements (slice of ints) are added, they are actually all there.
I've added some debugs and remodeled your program a bit, see if it makes sense:
package main
import (
"fmt"
)
func main() {
triangleNumber()
}
func combinations(sofar []int, rest []int, n int, matrix [][]int, count int) [][]int {
fmt.Println("Entered with matrix", matrix)
if n == 0 {
fmt.Println("Entered with count", count)
//Next two lines problematic
matrix = append(matrix, sofar)
count++
fmt.Println(sofar)
fmt.Println("Printing matrix\n***", matrix, "\n***")
return matrix
} else {
for i := range rest[:len(rest)] {
concat := sofar
concat = append(concat, rest[i])
matrix = combinations(concat, rest[i+1:], n-1, matrix, count)
fmt.Println("Sending with count", count)
}
}
return matrix
}
func factorial(x uint) uint {
if x == 0 {
return 1
}
return x * factorial(x-1)
}
func triangleNumber() int {
sofar := []int{}
rest := []int{1, 2, 3, 4}
matrixSize := factorial(4) / (factorial(1) * factorial(3))
matrix := make([][]int, 0)
count := 0
fmt.Println(matrixSize)
combinations(sofar, rest, 3, matrix, count)
return 0
}
And as you can see, you can pretty much get rid of count too with this approach (look at the output). There's still some scope for improvement left though, but I guess this addresses what you were asking.
On playground: https://play.golang.org/p/rnCdPcaIG3N
Hope this helps.
You're adding all to the first row, and you need to add to the next row, see:
Try this (with minimum change to your code: made count a pointer):
package main
import (
"fmt"
)
func main() {
triangleNumber()
}
func triangleNumber() int {
sofar := []int{}
rest := []int{1, 2, 3, 4}
matrixSize := factorial(4) / (factorial(1) * factorial(3))
matrix := make([][]int, matrixSize)
count := 0
fmt.Println(matrixSize)
combinations(sofar, rest, 3, matrix, &count)
fmt.Println(matrix)
return 0
}
func combinations(sofar []int, rest []int, n int, matrix [][]int, count *int) {
if n == 0 {
//Next two lines problematic
matrix[*count] = append(matrix[*count], sofar[0], sofar[1], sofar[2])
*count++
// fmt.Println(count, sofar)
} else {
for i := range rest[:len(rest)] {
concat := sofar
concat = append(concat, rest[i])
combinations(concat, rest[i+1:], n-1, matrix, count)
}
}
}
func factorial(x uint) uint {
if x == 0 {
return 1
}
return x * factorial(x-1)
}
output:
4
[[1 2 3] [1 2 4] [1 3 4] [2 3 4]]
Also for your special case, this works too:
matrix[*count] = []int{sofar[0], sofar[1], sofar[2]}
instead of:
matrix[*count] = append(matrix[*count], sofar[0], sofar[1], sofar[2])

how to understand the following code about golang slice?

Recently I found some code that I can't understand, below is my code:
func subsetsWithDup(nums []int) [][]int {
if len(nums) == 0 {
return [][]int{[]int{}}
}
sort.Ints(nums)
result := [][]int{}
backtracking(nums, &result, []int{}, 0)
return result
}
func backtracking(nums []int, result *[][]int, tempList []int, start int) {
*result = append(*result, tempList)
for i := start; i < len(nums); i++ {
if i > start && nums[i] == nums[i-1] {
continue
}
tempList = append(tempList, nums[i])
backtracking(nums, result, tempList, i+1)
tempList = tempList[:len(tempList)-1:len(tempList)-1]
}
}
and another approach:
func subsetsWithDup(nums []int) [][]int {
sort.Ints(nums)
return subsets(nums, []int{}, [][]int{})
}
func subsets(nums []int, result []int, results [][]int) [][]int {
newR := make([]int, len(result))
copy(newR, result)
results = append(results, newR)
if len(nums) == 0 {return results}
for i := 0; i < len(nums); i++ {
if i > 0 && nums[i] == nums[i - 1] {continue}
result = append(result, nums[i])
results = subsets(nums[i + 1:], result, results)
result = result[:len(result) - 1]
}
return results
}
In the first approach, I use the following code :
tempList = tempList[:len(tempList)-1:len(tempList)-1]
it works, but if I change it to:
tempList = tempList[:len(tempList)-1]
it dose not work.In the second approach which use copy function also works. I want to know what happens behind the code, any help is appreciated, thanks.
In Go, slice is a pointer type to maintain information about underlying array, so change of the underlying array would cause changes of the slice value, which sometimes might be surprising.
The second part of the puzzle is that append modifies the underlying array if the cap of the slice is sufficient. Document:
The append built-in function appends elements to the end of a slice.
If it has sufficient capacity, the destination is resliced to
accommodate the new elements. If it does not, a new underlying array
will be allocated. Append returns the updated slice. It is therefore
necessary to store the result of append, often in the variable holding
the slice itself.
So in you failed attempt, tempList = append(tempList, nums[i]) will possibly change value of previously stored slices in result.
On the other hand, the second approach creates a new slice with new underlying array and copy to it explictly, so the error is avoided. The first approach is more subtle, as it use a full slice expressions: tempList[:len(tempList)-1:len(tempList)-1]. The code limits the new slice's cap so append would have to allocate a new underlying array each time instead of using the orignal one.
More about full slice expressions(spec):
For an array, pointer to array, or slice a (but not a string), the primary expression
a[low : high : max]
constructs a slice of the same type, and with the same length and elements as the simple slice expression a[low : high]. Additionally, it controls the resulting slice's capacity by setting it to max - low. Only the first index may be omitted; it defaults to 0. After slicing the array a
a := [5]int{1, 2, 3, 4, 5}
t := a[1:3:5]
the slice t has type []int, length 2, capacity 4, and elements
t[0] == 2
t[1] == 3

Helper function to chunk any slice? [duplicate]

This question already has answers here:
Slice chunking in Go
(8 answers)
Closed 8 months ago.
I created a small helper function to split a large array of items into smaller arrays with a maximum size of n.
func toPackages(e []int, n int) [][]int {
var p [][]int
packets := int(math.Ceil(float64(len(e)) / float64(n)))
for i := 0; i < packets; i++ {
start := i * n
end := n * (i + 1)
if len(e) < end {
end = len(e)
}
p = append(p, e[start:end])
}
return p
}
Working example at Golang Playground.
In the program I have several different types of arrays I would like to split. I have tried converting it to using interfaces with interface{}.
It is pretty hard to make a generic function to handle this well. You will often spend as much code converting []int to []interface{} and back, as it is to just copy the snippet. I do have a slightly nicer way to do it though:
playground link
func splitInts(src []int, n int) (p [][]int){
for len(src) > n{
p = append(p,src[:n])
src = src[n:]
}
if(len(src) > 0){
p = append(p,src)
}
return p
}
Nothing in the function changes because of types, it can easily be copied to:
func splitStrings(src []string, n int) (p [][]string){
for len(src) > n{
p = append(p,src[:n])
src = src[n:]
}
if(len(src) > 0){
p = append(p,src)
}
return p
}
By only changing the first line.
Generally it is a good idea to just write the function for every type you need it for. This is also a matter of speed: if you use reflect to write a generic function it will not be as fast.
If you still want a generic function here it is:
func genToPackages(e interface{}, n int) interface{} {
t := reflect.TypeOf(e)
if t.Kind() != reflect.Slice {
log.Println("e has to be a slice")
}
v := reflect.ValueOf(e)
packets := int(math.Ceil(float64(v.Len()) / float64(n)))
p := reflect.MakeSlice(reflect.SliceOf(t), packets, packets)
for i := 0; i < packets; i++ {
s := reflect.MakeSlice(t, n, n)
start := i * n
for j := 0; j < n; j++ {
s.Index(j).Set(v.Index(j+start))
}
p.Index(i).Set(s)
}
return p.Interface()
}
You will have to cast the result to the type you expect. For example:
res := genToPackages([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5).([][]int)

unexpected slice append behaviour

I encountered weird behaviour in go code today: when I append elements to slice in loop and then try to create new slices based on the result of the loop, last append overrides slices from previous appends.
In this particular example it means that sliceFromLoop j,g and h slice's last element are not 100,101 and 102 respectively, but...always 102!
Second example - sliceFromLiteral behaves as expected.
package main
import "fmt"
func create(iterations int) []int {
a := make([]int, 0)
for i := 0; i < iterations; i++ {
a = append(a, i)
}
return a
}
func main() {
sliceFromLoop()
sliceFromLiteral()
}
func sliceFromLoop() {
fmt.Printf("** NOT working as expected: **\n\n")
i := create(11)
fmt.Println("initial slice: ", i)
j := append(i, 100)
g := append(i, 101)
h := append(i, 102)
fmt.Printf("i: %v\nj: %v\ng: %v\nh:%v\n", i, j, g, h)
}
func sliceFromLiteral() {
fmt.Printf("\n\n** working as expected: **\n")
i := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
fmt.Println("initial slice: ", i)
j := append(i, 100)
g := append(i, 101)
h := append(i, 102)
fmt.Printf("i: %v\nj: %v\ng: %v\nh:%v\n", i, j, g, h)
}
link to play.golang:
https://play.golang.org/p/INADVS3Ats
After some reading, digging and experimenting I found that this problem is originated in slices referencing the same underlaying array values and can be solved by copying slice to new one before appending anything, however it looks quite... hesitantly.
What's the idomatic way for creating many new slices based on old ones and not worrying about changing values of old slices?
Don't assign append to anything other than itself.
As you mention in the question, the confusion is due to the fact that append both changes the underlying array and returns a new slice (since the length might be changed). You'd imagine that it copies that backing array, but it doesn't, it just allocates a new slice object that points at it. Since i never changes, all those appends keep changing the value of backingArray[12] to a different number.
Contrast this to appending to an array, which allocates a new literal array every time.
So yes, you need to copy the slice before you can work on it.
func makeFromSlice(sl []int) []int {
result := make([]int, len(sl))
copy(result, sl)
return result
}
func main() {
i := make([]int, 0)
for ii:=0; ii<11; ii++ {
i = append(i, ii)
}
j := append(makeFromSlice(i), 100) // works fine
}
The slice literal behavior is explained because a new array is allocated if the append would exceed the cap of the backing array. This has nothing to do with slice literals and everything to do with the internals of how exceeding the cap works.
a := []int{1,2,3,4,5,6,7}
fmt.Printf("len(a) %d, cap(a) %d\n", a, len(a), cap(a))
// len(a) 7, cap(a) 7
b := make([]int, 0)
for i:=1; i<8, i++ {
b = append(b, i)
} // b := []int{1,2,3,4,5,6,7}
// len(b) 7, cap(b) 8
b = append(b, 1) // any number, just so it hits cap
i := append(b, 100)
j := append(b, 101)
k := append(b, 102) // these work as expected now
If you need a copy of a slice, there's no other way to do it other than, copying the slice. You should almost never assign the result of append to a variable other than the first argument of append. It leads to hard to find bugs, and will behave differently depending on whether the slice has the required capacity or not.
This isn't a commonly needed pattern, but as with all things of this nature if you need to repeate a few lines of code multiple times, then you can use a small helper function:
func copyAndAppend(i []int, vals ...int) []int {
j := make([]int, len(i), len(i)+len(vals))
copy(j, i)
return append(j, vals...)
}
https://play.golang.org/p/J99_xEbaWo
There is also a little bit simpler way to implement copyAndAppend function:
func copyAndAppend(source []string, items ...string) []string {
l := len(source)
return append(source[:l:l], items...)
}
Here we just make sure that source has no available capacity and so copying is forced.

Is this a reasonable and idiomatic GoLang circular shift implementation?

Can anyone comment on whether this is a reasonable and idiomatic way of implementing circular shift of integer arrays in Go? (I deliberately chose not to use bitwise operations.)
How could it be improved?
package main
import "fmt"
func main() {
a := []int{1,2,3,4,5,6,7,8,9,10}
fmt.Println(a)
rotateR(a, 5)
fmt.Println(a)
rotateL(a, 5)
fmt.Println(a)
}
func rotateL(a []int, i int) {
for count := 1; count <= i; count++ {
tmp := a[0]
for n := 1;n < len(a);n++ {
a[n-1] = a[n]
}
a[len(a)-1] = tmp
}
}
func rotateR(a []int, i int) {
for count := 1; count <= i; count++ {
tmp := a[len(a)-1]
for n := len(a)-2;n >=0 ;n-- {
a[n+1] = a[n]
}
a[0] = tmp
}
}
Rotating the slice one position at a time, and repeating to get the total desired rotation means it will take time proportional to rotation distance × length of slice. By moving each element directly into its final position you can do this in time proportional to just the length of the slice.
The code for this is a little more tricky than you have, and you’ll need a GCD function to determine how many times to go through the slice:
func gcd(a, b int) int {
for b != 0 {
a, b = b, a % b
}
return a
}
func rotateL(a []int, i int) {
// Ensure the shift amount is less than the length of the array,
// and that it is positive.
i = i % len(a)
if i < 0 {
i += len(a)
}
for c := 0; c < gcd(i, len(a)); c++ {
t := a[c]
j := c
for {
k := j + i
// loop around if we go past the end of the slice
if k >= len(a) {
k -= len(a)
}
// end when we get to where we started
if k == c {
break
}
// move the element directly into its final position
a[j] = a[k]
j = k
}
a[j] = t
}
}
Rotating a slice of size l right by p positions is equivalent to rotating it left by l − p positions, so you can simplify your rotateR function by using rotateL:
func rotateR(a []int, i int) {
rotateL(a, len(a) - i)
}
Your code is fine for in-place modification.
Don't clearly understand what you mean by bitwise operations. Maybe this
package main
import "fmt"
func main() {
a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
fmt.Println(a)
rotateR(&a, 4)
fmt.Println(a)
rotateL(&a, 4)
fmt.Println(a)
}
func rotateL(a *[]int, i int) {
x, b := (*a)[:i], (*a)[i:]
*a = append(b, x...)
}
func rotateR(a *[]int, i int) {
x, b := (*a)[:(len(*a)-i)], (*a)[(len(*a)-i):]
*a = append(b, x...)
}
Code works https://play.golang.org/p/0VtiRFQVl7
It's called reslicing in Go vocabulary. Tradeoff is coping and looping in your snippet vs dynamic allocation in this. It's your choice, but in case of shifting 10000 elements array by one position reslicing looks much cheaper.
I like Uvelichitel solution but if you would like modular arithmetic which would be O(n) complexity
package main
func main(){
s := []string{"1", "2", "3"}
rot := 5
fmt.Println("Before RotL", s)
fmt.Println("After RotL", rotL(rot, s))
fmt.Println("Before RotR", s)
fmt.Println("After RotR", rotR(rot,s))
}
func rotL(m int, arr []string) []string{
newArr := make([]string, len(arr))
for i, k := range arr{
newPos := (((i - m) % len(arr)) + len(arr)) % len(arr)
newArr[newPos] = k
}
return newArr
}
func rotR(m int, arr []string) []string{
newArr := make([]string, len(arr))
for i, k := range arr{
newPos := (i + m) % len(arr)
newArr[newPos] = k
}
return newArr
}
If you need to enter multiple values, whatever you want (upd code Uvelichitel)
package main
import "fmt"
func main() {
var N, n int
fmt.Scan(&N)
a := make([]int, N)
for i := 0; i < N; i++ {
fmt.Scan(&a[i])
}
fmt.Scan(&n)
if n > 0 {
rotateR(&a, n%len(a))
} else {
rotateL(&a, (n*-1)%len(a))
}
for _, elem := range a {
fmt.Print(elem, " ")
}
}
func rotateL(a *[]int, i int) {
x, b := (*a)[:i], (*a)[i:]
*a = append(b, x...)
}
func rotateR(a *[]int, i int) {
x, b := (*a)[:(len(*a)-i)], (*a)[(len(*a)-i):]
*a = append(b, x...)
}

Resources