Golang for loop continues counting - go

I am trying to make a for loop stop when a string contains a certain numeral. The only problem is it stops adding value to the string after adding 31 to the counter. I feel it is going to fast before it can play catch up. I know there's always another way to complete the task but I would just want to understand why it does this.
What I'm trying to accomplish is having the counter act as the height. The theSlice = 8 and webSlices is a list. The whole text says "Height is a 1" so I am trying to see what number is the height and make counter equal that.
Code:
func breakDownSlice(theSlice int, webSlices []string) {
counter := 0
done := false
for done == false {
log.Println(webSlices[theSlice])
log.Println(counter)
done = strings.Contains(webSlices[theSlice], string(counter))
if done == true {
log.Printf("The height is %d", counter)
} else {
counter++
}
}
}

the line
done = strings.Contains(webSlices[theSlice], string(counter))
string(counter) can't work here, use strconv.Itoa(counter) instead

Related

Golang, running for range loop on channel, how to continue execution of block having received next value from channel?

I'm studying Golang and now I'm stuck with a such situation.
Let's say I have a channel on ints:
ints = make(chan int)
And I keep receiving values after some period of time. So I'm running for range loop on my channel:
for update := range ints {
if update > 10 { // let's say update == 15 for example
// Here I want to continue execution of this block, however having
// the next value of update var, even though it will be <= 10.
// lets say next value is received and update == 5.
fmt.Println(update) // So this should print "5", not "10"
continue
} else {
fmt.Println("less than 10")
continue
}
}
So basically I want this block to sleep for some time until next value is received from channel and continue execution, given that update variable now has different value.
My first thoughts were to create smth like "isNewValueReceived" bool variable and use it to continue execution where I want. However, it seems to be wrong solution, since the logic of the program might get more complex.
Please, help me to find a solution of this problem. Thank you in advance!
UPD:
hasGoneAbove := false // initially set to false as no values have been received
hasGoneAbove2 := false
hasGoneAbove3 := false
hasGoneAbove3 := false
for update := range ints {
if hasGoneAbove{
doSomeJob()
hasGoneAbove = false
hasGoneAbove2 = true
continue
}
if hasGoneAbove2{
doSomeJob2()
hasGoneAbove2 = false
hasGoneAbove3 = true
continue
}
if hasGoneAbove3{
doSomeJob3()
hasGoneAbove3 = false
continue
}
if update > 10 {
hasGoneAbove = true
} else {
fmt.Println("less than 10")
}
}
Trying to make sense of your question, you seem to want to work with a state tracking variable:
hasGoneAbove := false // initially set to false as no values have been received
for update := range ints {
if hasGoneAbove{
fmt.Println(update)
hasGoneAbove = false
}
if update > 10 {
hasGoneAbove = true
} else {
fmt.Println("less than 10")
}
}
Updated:
With this sort of holding only the last value in memory:
var lastValue int // use zero value
for update := range ints {
if lastValue > 2{
doSomeJob2()
}
if hasGoneAbove > 3{
doSomeJob3()
}
if lastValue > 10{
doSomeJob()
} else {
fmt.Println("less than 10")
}
lastValue = update
}
Note: as per the code in your question, if the LastValue is 10 then all three functions are going to execute. Depending on how compute intensive they are you might want to run them in a goroutine.

Modify the index inside the `for` loop with a range in Rust

I'm looking at some code that looks like this:
for mut i in 2..points.len() {
// Do something
if some_condition {
i += 1;
}
}
It compiles and runs fine (it seems). My first intuition was that it would be better as a while loop.
Then I started wondering, is this something that's legal to do in Rust in general?
What happens if you happen to increment i beyond the range? I'm guessing trouble obviously...
I'd like to know if there are any kind of issues modifying the index while going through the range with it. I'm assuming that the i stays in range, but I would be interested to know what happens when it goes beyond the range too.
Your code
for mut i in 2..points.len() {
// Do something
if some_condition {
i += 1;
}
}
will internally in the compiler be rewritten in simpler terms using loop, into something like this:
let mut iter = (2..points.len()).into_iter();
loop {
if let Some(mut i) = iter.next() {
// Do something
if some_condition {
i += 1;
}
} else {
break
}
}
In this form, it should hopefully be more clear what actually happens here: i is declared inside of the loop body, and assigned the next value from the range iterator at the beginning of each iteration. If you modify it, it will just be reassigned on the next iteration. Specifically, you can't change i to affect anything outside of the current iteration of the loop.

How can I let a function randomly return either a true or a false in go

I want to have a function that I can call to get a random true or false on each call:
randBoolean() // true
randBoolean() // false
randBoolean() // false
randBoolean() // true
How can I return a random boolean?
You need some kind of random information, and based on its value, you can return true in half of its possible cases, and false in the other half of the cases.
A very simple example using rand.Float32() of the math/rand package:
func rand1() bool {
return rand.Float32() < 0.5
}
Don't forget to properly seed the math/rand package for it to be different on each app run using rand.Seed():
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println(rand1())
}
This is mentioned in the package doc of math/rand:
Use the Seed function to initialize the default Source if different behavior is required for each run.
If you don't seed, the same pseudo-random information is returned on each application run.
Some variations:
func rand2() bool {
return rand.Int31()&0x01 == 0
}
func rand3() bool {
return rand.Intn(2) == 0
}
And an interesting solution without using the math/rand package. It uses the select statement:
func rand9() bool {
c := make(chan struct{})
close(c)
select {
case <-c:
return true
case <-c:
return false
}
}
Explanation:
The select statement chooses one random case from the ones that can proceed without blocking. Since receiving from a closed channel can proceed immediately, one of the 2 cases will be chosen randomly, returning either true or false. Note that however this is far from being perfectly random, as that is not a requirement of the select statement.
The channel can also be moved to a global variable, so no need to create one and close one in each call:
var c = make(chan struct{})
func init() {
close(c)
}
func rand9() bool {
select {
case <-c:
return true
case <-c:
return false
}
}
This function returns true if the random integer is even else it returns false:
func randBool() bool{
return rand.Int() % 2 == 0
}
The easiest way will be to create a random number and then take its modulus of 2. Then if it is 0 the return true and if it is 1 then return false.
Here's another one liner, requires no random number generation/seeding etc., fairly simple :
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("Got random bool:", getRandBool())
}
func getRandBool() bool {
now := time.Now()
nowNano := now.Nanosecond()
fmt.Println(nowNano)
return now.UnixNano()%2 == 0
}
Edited after #icza's comments : time.Now() is supposed to return time with nanosecond accuracy, but on Windows 10 Pro 64-bit (and I tried with go 1.8 & it may be true with other Windows OS too) it always returns time with lesser precision (probably micro second), rounding off the result so that it'll end with xxxxx..00 and hence this function will return true always. I have modified the function so one can see the result also. Works fine on Linux & probably should on other Unix OS'es too. So either use this function only after testing or better don't use if you need to deploy on a Windows system. It's unfortunate and hard to believe this, but it's a reality, bad Windows implementation. Thanks #icza for pointing out.

Tour of Go Exercise #23: my word counter doesn't work

I'm trying to resolve the puzzle from go tour #23 and I don't understand why my word counter doesn't work. print seems to print the expected value but the tests sees only 1 regardless the count.
package main
import (
"strings"
"unicode/utf8"
"golang.org/x/tour/wc"
)
func WordCount(s string) map[string]int {
// explode the string into a slice without whitespaces
ws := strings.Fields(s)
//make a new map
c := make(map[string]int)
//iterate over each word
for _, v := range ws {
c[v] = utf8.RuneCountInString(v)
}
print(c["am"])
return c
}
func main() {
wc.Test(WordCount)
}
The playground is available here
You're solving the wrong problem. It doesn't ask you for the length of each word, but for the number of times each word occurs. Change
c[v] = utf8.RuneCountInString(v)
for
c[v] += 1 // or c[v]++
The problem is c[v] = utf8.RuneCountInString(v). It has two problems:
You're resetting the counter for each word every time you re-encounter it. You should increment, not set.
You are setting the number of runes in the word to the counter. The puzzle is "how many times a word appears in the text". so just do something like c[v] = c[v] + 1 (if the entry is empty it will default to 0)
Also, I'd normalize the text - strip punctuation marks and lowercase everything.

How do I do cursor-up in Go?

How do I do “cursor-up” in Go? (Clear-to-end-of-line would also be good to know). (All platforms).
To elaborate and show the context, I’m writing a test program in Go that requires the input of some parameters (via console) that are stored in a text file and used as defaults for the next usage. I want to have some very rudimentary console “editing” features.
Currently it is fairly primitive because I don’t want to go deeply into console editing, I just want something fairly basic but also not too basic.
In the example below from my test program, the String variable “sPrompt” contains the prompt for the input, and to the right it shows the default and then there are backspace characters to position the cursor so that the default is not overwritten – like I said, very basic.
When the operator enters the input, if an error, I'd like to display an error message, and then in either case move the cursor up to the line just displayed/entered and if an error, then display the original line, or if correct, display just the prompt and the new parameter.
I did read somewhere that ReadLine() should be avoided, but it appears to do the job.
Example:
func fInputString(sPrompt string, asValid []string, sDefault string)
(sInput string, tEnd bool) {
oBufReader := bufio.NewReader(os.Stdin)
for {
print("\n" + sPrompt)
vLine, _, _ := oBufReader.ReadLine()
sInput = strings.ToLower(string(vLine))
if sInput == "end" {
return "", true
}
if sInput == "" {
sInput = sDefault
}
// check for valid input //
for _, sVal := range asValid {
if sInput == sVal {
return sInput, false
}
}
}
}
This is how sPrompt is constructed (not meant to be optimized):
if sDefault != "" {
for len(sPrompt) < 67 {
sPrompt += " "
}
sPrompt += sDefault
for iBack := 20 + len(sDefault); iBack > 0; iBack-- {
sPrompt += "\b"
}
}
With tput strings that control the cursor around the screen:
tput sc to save the cursor position
tput rc to restore the cursor position
Then using these strings in the Go function:
package main
import (
"fmt"
"time"
)
const sc = "\u001B7"
const rc = "\u001B8"
func main() {
fmt.Print(sc)
for i := 1; i <= 10; i++ {
fmt.Print(rc + sc)
fmt.Println(i, "one")
fmt.Println(i, "two")
fmt.Println(i, "three")
fmt.Println(i, "four")
fmt.Println(i, "five")
time.Sleep(time.Second)
}
}
Should work in most terminals.
Make your own little shell
You should not reinvent the wheel and use a library which does exactly what you want.
A popular option is the readline library which is apparently available for Windows
as well. This is used, for example, by bash and ZSH. There are some Go wrappers for it:
https://github.com/shavac/readline
https://github.com/bobappleyard/readline
I personally would recommend bobappleyard/readline as it is better documented
and has a nicer API (less C-like). There does not seem to be a special build tag for
Windows, so you might have to write it for yourself but that should be not that hard.
termbox and its (pure) Go implementation termbox-go which was already pointed out by #bgp does not seem to be good for simply reading a line as it seems to be more intended
for full screen console applications. Also, you would have to code the up/down matching
and history yourself.
.Readline()
The doc is right by saying that you should not use this as it does not handle anything for
you. For example, reading from a stream that emits partial data, you have no guarantee that you will get a full line from Readline. Use ReadSlice('\n') for that.

Resources