Initialize golang slice with int numbers from 0 to N - go

I am almost certain that I read about a simple "tricky" way to initialize slice of ints with the numbers from 0 to N, but I cannot find it anymore.
What is the simplest way to do this?

You just use make passing N for the length then use a simple for loop to set the values...
mySlice := make([]int, N)
for i := 0; i < N; i++ {
mySlice[i] = i
}
Here's a full example on play; https://play.golang.org/p/yvyzuWxN1M

Related

How to swap two slices in a byte array?

I try to swap the slice 0:10 and the slice 10:20 using the following code. But
data1 := make([]byte, 100)
tmp := data1[0:10]
data1[0:10] = data1[10:20]
data1[10:20] = tmp
But I got error messages like this.
../xxx.go:60:14: cannot assign to data1[0:10]
../xxx.go:61:15: cannot assign to data1[10:20]
Could anybody show me how to swap two slices in a byte array? Thanks.
You are trying to swap the contents of the underlying array. The only way of doing it is to swap individual elements:
for i := 0; i < 10; i++ {
data[i], data[i+10] = data[i+10], data[i]
}
Or:
j := 10
for i := 0; i < 10; i++ {
data[i], data[j] = data[j], data[i]
j++
}
#BurakSerdar 's answer is the most efficient for the small chunks of data to move and the swap nature of the operation.
If you're curious how to copy sections of a slice, simply use the internal copy function:
copy(data[0:10], data[10:20]) // overwrites first 10-bytes with next 10 bytes
To perform a swap with copy is a little awkward, but if you're curious:
// tmp := data[0:10] // will *NOT* work
// // as `tmp` will just reference data's underlying byte-array
tmp := make([]byte, 10) // need fresh memory
copy(tmp, data[0:10])
copy(data[0:10], data[10:20])
copy(data[10:20], tmp)
https://play.golang.org/p/ud31Gxfa19b

Efficient allocation of slices (cap vs length)

Assuming I am creating a slice, which I know in advance that I want to populate via a for loop with 1e5 elements via successive calls to append:
// Append 1e5 strings to the slice
for i := 0; i<= 1e5; i++ {
value := fmt.Sprintf("Entry: %d", i)
myslice = append(myslice, value)
}
which is the more efficient way of initialising the slice and why:
a. declaring a nil slice of strings?
var myslice []string
b. setting its length in advance to 1e5?
myslice = make([]string, 1e5)
c. setting both its length and capacity to 1e5?
myslice = make([]string, 1e5, 1e5)
Your b and c solutions are identical: creating a slice with make() where you don't specify the capacity, the "missing" capacity defaults to the given length.
Also note that if you create the slice with a length in advance, you can't use append() to populate the slice, because it adds new elements to the slice, and it doesn't "reuse" the allocated elements. So in that case you have to assign values to the elements using an index expression, e.g. myslice[i] = value.
If you start with a slice with 0 capacity, a new backing array have to be allocated and "old" content have to be copied over whenever you append an element that does not fit into the capacity, so that solution must be slower inherently.
I would define and consider the following different solutions (I use an []int slice to avoid fmt.Sprintf() to intervene / interfere with our benchmarks):
var s []int
func BenchmarkA(b *testing.B) {
for i := 0; i < b.N; i++ {
s = nil
for j := 0; j < 1e5; j++ {
s = append(s, j)
}
}
}
func BenchmarkB(b *testing.B) {
for i := 0; i < b.N; i++ {
s = make([]int, 0, 1e5)
for j := 0; j < 1e5; j++ {
s = append(s, j)
}
}
}
func BenchmarkBLocal(b *testing.B) {
for i := 0; i < b.N; i++ {
s := make([]int, 0, 1e5)
for j := 0; j < 1e5; j++ {
s = append(s, j)
}
}
}
func BenchmarkD(b *testing.B) {
for i := 0; i < b.N; i++ {
s = make([]int, 1e5)
for j := range s {
s[j] = j
}
}
}
Note: I use package level variables in benchmarks (except BLocal), because some optimization may (and actually do) happen when using a local slice variable).
And the benchmark results:
BenchmarkA-4 1000 1081599 ns/op 4654332 B/op 30 allocs/op
BenchmarkB-4 3000 371096 ns/op 802816 B/op 1 allocs/op
BenchmarkBLocal-4 10000 172427 ns/op 802816 B/op 1 allocs/op
BenchmarkD-4 10000 167305 ns/op 802816 B/op 1 allocs/op
A: As you can see, starting with a nil slice is the slowest, uses the most memory and allocations.
B: Pre-allocating the slice with capacity (but still 0 length) and using append: it requires only a single allocation and is much faster, almost thrice as fast.
BLocal: Do note that when using a local slice instead of a package variable, (compiler) optimizations happen and it gets a lot faster: twice as fast, almost as fast as D.
D: Not using append() but assigning elements to a preallocated slice wins in every aspect, even when using a non-local variable.
For this use case, since you already know the number of string elements that you want to assign to the slice,
I would prefer approach b or c.
Since you will prevent resizing of the slice using these two approaches.
If you choose to use approach a, the slice will double its size everytime a new element is added after len equals capacity.
https://play.golang.org/p/kSuX7cE176j

Sort an array with strings and numbers

I passed few hours searching about a lib or a way to do this:
I have an array []string{"ex10", "ex2", "ex1"} and after call the sort.Strings or using sort.Slice to compare with an array of bytes I get the result []string{"ex1", "ex10", "ex2"}
anyone has an idea how to implement this?
if anyone knows swift I've found the solution here
If you don't want the numbers sorted lexicographically, you need to separate them from the strings and parse them as integers.
This example assumes there is always a 2 letter prefix with a valid number, and slices the string accordingly: https://play.golang.org/p/LaX-pTr6etc
s := []string{"ex10", "ex2", "ex1"}
sort.Slice(s, func(i, j int) bool {
if s[i][:2] != s[j][:2] {
return s[i] < s[j]
}
ii, _ := strconv.Atoi(s[i][2:])
jj, _ := strconv.Atoi(s[j][2:])
return ii < jj
})

For loop of two variables in Go

The following for loop in Go isn't allowed,
for i := 0, j := 1; i < 10; i++, j++ {...}
What's the correct equivalent of the for-loop of two variables below?
for (int i = 0, j = 1; i < 10; i ++ , j ++) {...}
You don't have a comma operator to join multiple statements, but you do have multiple assignment, so this works:
package main
import (
"fmt"
)
func main() {
for i, j := 0, 1; i < 10; i, j = i+1, j+1 {
fmt.Println("Hello, playground")
}
}
Although above Answer is accepted, and it fully satisfy the need. But I would like to contribute some further explanation to it.
Golang Does not support many things which could be done in simple terms. For loop is a most common example of this. The beauty of Go's For loop is that it merges many modern style of looping into one keyword.
Similarly Golang do with Multiple Variable declaration and assignment. According to above mentioned problem, We could solve multi-variable for loop with this simple tool which Golang provides us. If you want to look into further explanation, this question provide further details and way of declaring multiple variables in one statement.
Coming back to for loop, If we want to declare variable of same datatype we can declare them with this
var a,b,c string
but we use short hand in for loop so we can do this for initializing them with same value
i,j := 0,1
Different Datatypes and Different Values
and if we want to declare different type of variables and want to assign different values we can do this by separating variables names and after := different values by comma as well. for example
c,i,f,b := 'c',23423,21.3,false
Usage of Assignment Operator
Later on, we can assign values to multiple variables with the same approach.
x,y := 10.3, 2
x,y = x+10, y+1
Mixing Struct and Normal types in single statement
Even we can use struct types or pointers the same way. Here is a function to iterate Linked list which is defined as a struct
func (this *MyLinkedList) Get(index int) int {
for i,list := 0,this; list != nil; i,list = i+1,list.Next{
if(i==index){
return list.Val
}
}
return -1
}
This list is defined as
type MyLinkedList struct {
Val int
Next *MyLinkedList
}
Answering to Original Problem
Coming to the origin Question, Simply it could be done
for i, j := 0, 1; i < 10; i, j = i+1, j+1 {
fmt.Println("i,j",i,j)
}
Suppose you want to loop using two different starting index, you can do this way.
This is the example to check if string is palindrome or not.
name := "naman"
for i<len(name) && j>=0{
if string(name[i]) == string(name[j]){
i++
j--
continue
}
return false
}
return true
This way you can have different stopping conditions and conditions will not bloat in one line.
As pointed by Mr. Abdul, for iterate among two variable you can use the following construct:
var step int = 4
for row := 0; row < rowMax; row++ {
for col := 0; col < colMax; col++ {
for rIndex, cIndex := row, col; rIndex <= row+step && cIndex <= col; rIndex, cIndex = rIndex+1, cIndex+1 {
}
}
}

Go: builtin make - does the capacity make a difference

Consider wanting to dynamically fill an array/slice with exactly 5 elements. No more, and no less.
(1) Slice with initial length 0
sl := []string{}
for i := 0; i < 5; i++ {
sl = append(sl, "abc")
}
(2) Slice with initial length set, no capacity
sl := make([]string, 5)
for i := 0; i < 5; i++ {
s1[i] = "abc"
}
(3) Slice with initial length set, capacity given
sl := make([]string, 5, 5)
for i := 0; i < 5; i++ {
sl[i] = "abc"
}
My feeling tells me that #1 is not the best solution, but I am wondering why I would choose #2 over #3 or vice versa? (performance-wise)
First of all, whenever you have a question about performance, benchmark and profile.
Secondly, I don't see any difference here. Considering that this code
s := make([]int, 5)
fmt.Println(cap(s))
prints 5, your #2 and #3 are basically the same.

Resources