Go, Press return to continue - go

I have a program that is taking an array and shuffling it, once it has done this it will print out one of the first value from the shuffled array. Once it prints out the value I want to it display a 'Press return to continue' message will be displayed. This message will presist until the user presses return, then it will get the next value from the shuffled array.
I have a script working fine for the first value but after I press return it just creates empty lines in my terminal.
Here is my example:
package main
import (
"bufio"
"fmt"
"math/rand"
"os"
"time"
)
func main() {
users := make(map[int]string)
users[0] = "Mike"
users[1] = "Paul"
users[2] = "Steve"
users[3] = "Lawrence"
users[4] = "Stephen"
users[5] = "James"
getNextSpeaker(users)
}
func getNextSpeaker(users map[int]string) {
numUsers := len(users)
list := randList(1, numUsers)
for _, element := range list {
fmt.Println(users[element-1])
pressAnyKey()
}
}
func randList(min, max int) []int {
if max < min {
min, max = max, min
}
length := max - min + 1
t0 := time.Now()
rand.Seed(int64(t0.Nanosecond()))
list := rand.Perm(length)
for index, _ := range list {
list[index] += min
}
return list
}
func pressAnyKey() string {
fmt.Println("Press Return To Continue...")
reader := bufio.NewReader(os.Stdin)
input, err := reader.ReadString('.')
if err != nil {
panic(err)
}
return input
}
Terminal Output:
$ go run src/RandomMeetingSpeaker/meeting.go
Paul
Press Return To Continue...
<empty line...>
<empty line...>
<empty line...>
<empty line...>
<empty line...>
etc etc

ReadString takes the delimiter byte. In your case, that's a newline, not a dot. Simply replace the line
input, err := reader.ReadString('.')
with
input, err := reader.ReadString('\n')
and it will work.

Related

Go's `fmt.Println()` overprints previous lines read from a file with `bufio` `Scanner`

This is a small snippet of code supposed to read a list of space-separated values of first name and last name from a text file and put the result into a slice in Go. For some reason, only the first item is stored in the slice:
package main
import (
"fmt"
"bufio"
"os"
//"io"
//"strings"
)
type Person struct {
fName string
lName string
}
func main() {
// a scanner to read input with spaces
scanner := bufio.NewScanner(os.Stdin)
fmt.Print("Enter a file name: ")
scanner.Scan()
fileName := scanner.Text()
scanner = nil //close this scanner
file, err := os.Open(fileName)
if err != nil {
fmt.Fprintf(os.Stderr, "os.Open error: %v\n", err)
return
}
fmt.Println() //empty string
fileScanner := bufio.NewScanner(file)
fileScanner.Split(bufio.ScanLines)
var persons []Person = make([]Person, 0, 3)
for fileScanner.Scan() {
line := fileScanner.Text()
fmt.Println(line)
var (
firstName string
lastName string
)
fmt.Sscanln(line, &firstName, &lastName)
person := Person{truncateString(firstName, 20), truncateString(lastName, 20)}
persons = append(persons, person)
}
file.Close()
fmt.Println("Items: ", len(persons))
for i, element := range persons {
fmt.Printf("%v %s %s\n", i, element.fName, element.lName)
}
}
func truncateString(input string, length int) string {
if len(input) > length {
return string(input[0:length])
} else {
return input
}
}
To debug it I added an fmt.Println() to print out the lines of the input file. Surprisingly, it does not print the strings on new lines, but rather, as far as I can judge from the output, it overwrites the strings over the same line.
For the input file:
Harper Collins
Billy Bons
John Bon Jovi
It gives the output:
Enter a file name: names.txt
John Bon Jovis
1
0 Harper Collins
The last s is obviously from a longer name overwritten.
What can be the reason?

How do I keep Scan from reading all characters from a user input in GO?

I am currently trying to validate user input for a random team generator. The user inputs the number of team members per team and the program breaks up the list of names into teams. If I put in a string it outputs an error message for each character in the string. I want it to output just one error message even if I type several characters.
//Dan Bell
//Random team generator
package main
import (
"bufio"
"fmt"
"log"
"math/rand"
"os"
"strings"
"time"
)
func main() {
var my_slice []string
// open the names.txt file contained in the same directory
f, err := os.Open("names.txt")
if err != nil {
log.Fatal(err)
}
defer f.Close()
//scan the contents of the .txt file into a slice
scanner := bufio.NewScanner(f)
for scanner.Scan() {
my_slice = append(my_slice, scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
//shuffle the slice so that the groups are random each time
rand.Seed(time.Now().UnixNano())
rand.Shuffle(len(my_slice), func(i, j int) { my_slice[i], my_slice[j] = my_slice[j], my_slice[i] })
fmt.Println("\nWelcome to our team generator" + "\n\n\n" + "How big should the teams be?")
var teamSize int
//put the user input into the teamSize variable
//validate input
for {
_, err := fmt.Scan(&teamSize)
if err != nil {
fmt.Println("\nEnter a valid number")
} else {
break
}
}
// fmt.Scanln(&teamSize)
var divided [][]string
//chop the slice into chunks sized using the teamSize entered by a user
for i := 0; i < len(my_slice); i += teamSize {
end := i + teamSize
if end > len(my_slice) {
end = len(my_slice)
}
divided = append(divided, my_slice[i:end])
}
//print each group
for i := 0; i < len(divided); i++ {
fmt.Println("\nGroup " + fmt.Sprint(i+1) + "\n" + strings.Join(divided[i], ", "))
}
}

How to convert strings to lower case in GO?

I am new to the language GO and working on an assignment where i should write a code that return the word frequencies of the text. However I know that the words 'Hello', 'HELLO' and 'hello' are all counted as 'hello', so I need to convert all strings to lower case.
I know that I should use strings.ToLower(), however I dont know where I should Included that in the class. Can someone please help me?
package main
import (
"fmt"
"io/ioutil"
"log"
"strings"
"time"
)
const DataFile = "loremipsum.txt"
// Return the word frequencies of the text argument.
func WordCount(text string) map[string]int {
fregs := make(map[string]int)
words := strings.Fields(text)
for _, word := range words {
fregs[word] += 1
}
return fregs
}
// Benchmark how long it takes to count word frequencies in text numRuns times.
//
// Return the total time elapsed.
func benchmark(text string, numRuns int) int64 {
start := time.Now()
for i := 0; i < numRuns; i++ {
WordCount(text)
}
runtimeMillis := time.Since(start).Nanoseconds() / 1e6
return runtimeMillis
}
// Print the results of a benchmark
func printResults(runtimeMillis int64, numRuns int) {
fmt.Printf("amount of runs: %d\n", numRuns)
fmt.Printf("total time: %d ms\n", runtimeMillis)
average := float64(runtimeMillis) / float64(numRuns)
fmt.Printf("average time/run: %.2f ms\n", average)
}
func main() {
// read in DataFile as a string called data
data, err:= ioutil.ReadFile("loremipsum.txt")
if err != nil {
log.Fatal(err)
}
// Convert []byte to string and print to screen
text := string(data)
fmt.Println(text)
fmt.Printf("%#v",WordCount(string(data)))
numRuns := 100
runtimeMillis := benchmark(string(data), numRuns)
printResults(runtimeMillis, numRuns)
}
You should convert words to lowercase when you are using them as map key
for _, word := range words {
fregs[strings.ToLower(word)] += 1
}
I get [a:822 a.:110 I want all a in the same. How do i a change the code so that a and a. is the same? – hello123
You need to carefully define a word. For example, a string of consecutive letters and numbers converted to lowercase.
func WordCount(s string) map[string]int {
wordFunc := func(r rune) bool {
return !unicode.IsLetter(r) && !unicode.IsNumber(r)
}
counts := make(map[string]int)
for _, word := range strings.FieldsFunc(s, wordFunc) {
counts[strings.ToLower(word)]++
}
return counts
}
to remove all non-word characters you could use a regular expression:
package main
import (
"bufio"
"fmt"
"log"
"regexp"
"strings"
)
func main() {
str1 := "This is some text! I want to count each word. Is it cool?"
re, err := regexp.Compile(`[^\w]`)
if err != nil {
log.Fatal(err)
}
str1 = re.ReplaceAllString(str1, " ")
scanner := bufio.NewScanner(strings.NewReader(str1))
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
fmt.Println(strings.ToLower(scanner.Text()))
}
}
See strings.EqualFold.
Here is an example.

How to recursively capture user input

I'm trying to capture the input of a bunch of numbers in Go. I am not allowed to do for loops. User input is multi-lined. However the function below is not returning the expected results of an []int, it instead returns with an empty array. Why is this? Or is there another way to capture multi-lined user input without for loops?
func input_to_list() []int {
fmt.Print("continuously enter text: ")
reader := bufio.NewReader(os.Stdin)
user_input, _ := reader.ReadString('\n')
print(user_input)
var result []int
if user_input == "\n" {
return result
}
return append(result, input_to_list()...)
}
How to recursively capture user input?
I am not allowed to do for loops.
For example,
package main
import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
)
func readInt(rdr *bufio.Reader, n []int) []int {
line, err := rdr.ReadString('\n')
line = strings.TrimSpace(line)
if i, err := strconv.Atoi(line); err == nil {
n = append(n, i)
}
if err == io.EOF || strings.ToLower(line) == "end" {
return n
}
return readInt(rdr, n)
}
func ReadInts() []int {
fmt.Print("enter integers:\n")
var n []int
rdr := bufio.NewReader(os.Stdin)
return readInt(rdr, n)
}
func main() {
n := ReadInts()
fmt.Println(n)
}
Output:
enter integers:
42
7
end
[42 7]
Your function never assigns any value to result.
func input_to_list() []int {
/* ... */
var result []int // Create empty `result` slice
if user_input == "\n" {
return result // Return empty result slice
}
return append(result, input_to_list()...) // Combine two empty slices, and return the (still) empty slice
}
Let's step through:
You create an empty slice called result
If user_input is empty, you return the result immediately.
If user_input is not empty, you call input_to_list() recursively, and add its (empty) result to your empty result, then return that (still) empty result.
To get your desired behavior, you should be doing something (other than just checking for empty) with user_input. Probably something related to strconv.Atoi or similar, then adding that to result.

Convert slice of string input from console to slice of numbers

I'm trying to write a Go script that takes in as many lines of comma-separated coordinates as the user wishes, split and convert the string of coordinates to float64, store each line as a slice, and then append each slice in a slice of slices for later usage.
Example inputs are:
1.1,2.2,3.3
3.14,0,5.16
Example outputs are:
[[1.1 2.2 3.3],[3.14 0 5.16]]
The equivalent in Python is
def get_input():
print("Please enter comma separated coordinates:")
lines = []
while True:
line = input()
if line:
line = [float(x) for x in line.replace(" ", "").split(",")]
lines.append(line)
else:
break
return lines
But what I wrote in Go seems way too long (pasted below), and I'm creating a lot of variables without the ability to change variable type as in Python. Since I literally just started writing Golang to learn it, I fear my script is long as I'm trying to convert Python thinking into Go. Therefore, I would like to ask for some advice as to how to write this script shorter and more concise in Go style? Thank you.
package main
import (
"fmt"
"os"
"bufio"
"strings"
"strconv"
)
func main() {
inputs := get_input()
fmt.Println(inputs)
}
func get_input() [][]float64 {
fmt.Println("Please enter comma separated coordinates: ")
var inputs [][]float64
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
if len(scanner.Text()) > 0 {
raw_input := strings.Replace(scanner.Text(), " ", "", -1)
input := strings.Split(raw_input, ",")
converted_input := str2float(input)
inputs = append(inputs, converted_input)
} else {
break
}
}
return inputs
}
func str2float(records []string) []float64 {
var float_slice []float64
for _, v := range records {
if s, err := strconv.ParseFloat(v, 64); err == nil {
float_slice = append(float_slice, s)
}
}
return float_slice
}
Using only string functions:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
var result [][]float64
var txt string
for scanner.Scan() {
txt = scanner.Text()
if len(txt) > 0 {
values := strings.Split(txt, ",")
var row []float64
for _, v := range values {
fl, err := strconv.ParseFloat(strings.Trim(v, " "), 64)
if err != nil {
panic(fmt.Sprintf("Incorrect value for float64 '%v'", v))
}
row = append(row, fl)
}
result = append(result, row)
}
}
fmt.Printf("Result: %v\n", result)
}
Run:
$ printf "1.1,2.2,3.3
3.14,0,5.16
2,45,76.0, 45 , 69" | go run experiment2.go
Result: [[1.1 2.2 3.3] [3.14 0 5.16] [2 45 76 45 69]]
With given input, you can concatenate them to make a JSON string and then unmarshal (deserialize) that:
func main() {
var lines []string
for {
var line string
fmt.Scanln(&line)
if line == "" {
break
}
lines = append(lines, "["+line+"]")
}
all := "[" + strings.Join(lines, ",") + "]"
inputs := [][]float64{}
if err := json.Unmarshal([]byte(all), &inputs); err != nil {
fmt.Println(err)
return
}
fmt.Println(inputs)
}

Resources