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 {
}
}
}
Related
In some cases when i == len(SliceA) i get a slice out of bounds error.
//filterIntersection removes points from two slices that have common points.
func filterIntersection(sliceA, sliceB *[]ds.Coord) {
for i, a := range *sliceA {
for j, b := range *sliceB {
if a == b {
(*sliceA) = append((*sliceA)[:i], (*sliceA)[i+1:]...) <--- error here
(*sliceB) = append((*sliceB)[:j], (*sliceB)[j+1:]...)
}
}
}
}
Well if i == len(SliceA), then sliceA[i+1] is out of bounds! It is not "in some cases" but in every case, and the same will happen for SliceB.
Consider breaking out of your loop if i == len(SliceA) or j == len(SliceB).
Another solution would be to use a "regular" for loop: for i := 0; i < len(SliceA); i++
I'm trying to solve a couple of example programming problems to familiarize myself with the language.
I am iterating over a string as follows:
func main() {
fullFile := "abcdDefF"
for i := 1; i < len(fullFile); i++ {
println(fullFile[i-1], fullFile[i], fullFile[i-1]-fullFile[i])
}
}
In the loop I want to get the difference between the current rune and the previous rune (trying to identify lower-case - upper-case pairs by finding any pairs where the difference is == 32.
Strangely, the subtraction doesn't work properly (in fact seems to yield addition in cases where I would expect a negative number) although I would expect it to since runes are represented by int32.
Figured it out: the data type returned was a byte.
Explicitly converted to int and everything works as expected.
func main() {
fullFile, _ := ioutil.ReadFile("input/input.txt")
previous := 0
current := 0
for i := 1; i < len(fullFile); i++ {
previous = int(fullFile[i-1])
current = int(fullFile[i])
println(current, previous, current-previous)
}
}
I'm doing an exercise on Go that asks me to print a letter like this
G
GG
GGG
GGGG
GGGGG
for 25 different lines, and adding one more letter each time.
I'm asked to solve it one time using only one for loop, and then again but with two for loops. I already solved both, but even though my code using two for loops works gives the right output, I think it's weird and not ok:
func manyG2() {
var counter string
for i := 0; i <= 24; i++ {
for x := 0; x == 0; x++ {
counter += "G"
fmt.Println(counter)
}
}
}
How other way can I write it with two for loops?
Here is the another way to do it, instead of concatenating every time to the string ...
func manyG2() {
for i := 0; i < 25; i++ {
for j := 0; j <= i; j++ { // num of Gs are equal to the row no.
fmt.Print("G")
}
fmt.Println()
}
}
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
An idiomatic method to remove an element i from a slice a, preserving the order, seems to be:
a = append(a[:i], a[i+1:]...)
I was wondering which would be the best way to do it inside a loop. As I understand, it is not possible to use it inside a range for:
for i := range a { // BAD
if conditionMeets(a[i]) {
a = append(a[:i], a[i+1:]...)
}
}
However it is possible to use len(a). [EDIT: this doesn't work, see answers below]
for i := 0; i < len(a); i++ {
if conditionMeets(a[i]) {
a = append(a[:i], a[i+1:]...)
}
}
Is there a better or more idiomatic way than using len or append?
Your proposed solution is incorrect. The problem is that when you remove an element from a slice, all subsequent elements are shifted. But the loop doesn't know that you changed the underlying slice and loop variable (the index) gets incremented as usual, even though in this case it shouldn't because then you skip an element.
And if the slice contains 2 elements which are right next to each other both of which need to be removed, the second one will not be checked and will not be removed.
So if you remove an element, the loop variable has to be decremented manually! Let's see an example: remove words that start with "a":
func conditionMeets(s string) bool {
return strings.HasPrefix(s, "a")
}
Solution (try it with all other examples below on the Go Playground):
a := []string{"abc", "bbc", "aaa", "aoi", "ccc"}
for i := 0; i < len(a); i++ {
if conditionMeets(a[i]) {
a = append(a[:i], a[i+1:]...)
i--
}
}
fmt.Println(a)
Output:
[bbc ccc]
Or better: use a downward loop and so you don't need to manually decrement the variable, because in this case the shifted elements are in the "already processed" part of the slice.
a := []string{"abc", "bbc", "aaa", "aoi", "ccc"}
for i := len(a) - 1; i >= 0; i-- {
if conditionMeets(a[i]) {
a = append(a[:i], a[i+1:]...)
}
}
fmt.Println(a)
Output is the same.
Alternate for many removals
If you have to remove "many" elements, this might be slow as you have to do a lot of copy (append() does the copy). Imagine this: you have a slice with 1000 elements; just removing the first element requires copying 999 elements to the front. Also many new slice descriptors will be created: every element removal creates 2 new slice descriptors (a[:i], a[i+1:]) plus a has to be updated (the result of append()). In this case it might be more efficient to copy the non-removable elements to a new slice.
An efficient solution:
a := []string{"abc", "bbc", "aaa", "aoi", "ccc"}
b := make([]string, len(a))
copied := 0
for _, s := range(a) {
if !conditionMeets(s) {
b[copied] = s
copied++
}
}
b = b[:copied]
fmt.Println(b)
This solution allocates a slice with the same length as the source, so no new allocations (and copying) will be performed. This solution can also use the range loop. And if you want the result in a, assign the result to a: a = b[:copied].
Output is the same.
In-place alternate for many removals (and for general purposes)
We can also do the removal "in place" with a cycle, by maintaining 2 indices and assigning (copying forward) non-removable elements in the same slice.
One thing to keep in mind is that we should zero places of removed elements in order to remove references of unreachable values so the GC can do its work. This applies to other solutions as well, but only mentioned here.
Example implementation:
a := []string{"abc", "bbc", "aaa", "aoi", "ccc"}
copied := 0
for i := 0; i < len(a); i++ {
if !conditionMeets(a[i]) {
a[copied] = a[i]
copied++
}
}
for i := copied; i < len(a); i++ {
a[i] = "" // Zero places of removed elements (allow gc to do its job)
}
a = a[:copied]
fmt.Println(a)
Output is the same. Try all the examples on the Go Playground.