Attempting to exit on key character press with an enter afterwards

Hi

inputReader.ReadRune() will read the next rune and return its character code so if you write A will you get the rune 60. If you want to read numbers as strings and then convert them you could read from stdin with bufio.Scanner

bufio.NewScanner(os.stdin) - creates a new scanner
scanner.Scan() waits until where is more input (user pressed return)
scanner.Text() get the text entered

https://golang.org/pkg/strconv/ has functions to convert strings to numbers
https://golang.org/pkg/sort/ has funtions to sort slices of integers

and finally you can use append to expand a slice

Hope I pointed you in some correct directions and don’t hesitate to come back and ask again :slight_smile:

1 Like

@johandalabacka you did point me in the right direction. Thanks! I will keep trying. Thanks!

1 Like

@FistOfJustice Thanks for the extra explanation. I understand your problem now, but it looks like Johan already gave you a good answer. Let us know if you need more help.

1 Like

@jayts, thanks my friend, I surely will!

About how append() reallocates slices…

Be careful to understand the difference between the length of a slice and it’s capacity. Go has built-in functionslen() and cap() to get these two numbers. The length is how many things you have in the slice, and the capacity is how many spaces the slice has available (that is, how much space was allocated).

When append() reallocates, it doesn’t just add one more space and put the next thing into it. It allocates for a greater capacity, so the next time you append something, it won’t have to reallocate again. It will do that if you keep appending things, and each time it runs out of space and needs to reallocate, it will add more extra space than the previous time.

You can modify your program to watch the length and capacity of your slice as you continue to add integers to it. That might be somewhat enlightening. :wink:

1 Like

Thanks @jayts! I am running into some issues with my program. I have modified the code for now to test for the ‘X’ char and then to add the number to the slice if it is not ‘X’. I have not tried append yet to dynamically add more space (kind of like an ArrayList add method in Java). Please have a look at the code and the ouput:

// Write a program which prompts the user to enter integers and stores the integers in a sorted slice.
// The program should be written as a loop. Before entering the loop, the program should create an empty
// integer slice of size (length) 3. During each pass through the loop, the program prompts the user to enter an
// integer to be added to the slice. The program adds the integer to the slice, sorts the slice, and prints
// the contents of the slice in sorted order. The slice must grow in size to accommodate any number of integers
// which the user decides to enter. The program should only quit (exiting the loop) when the user enters the
// character ‘X’ instead of an integer.

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	userSlice := make([]int, 3) //Create a Slice of size 3

	inputReader := bufio.NewReader(os.Stdin)

	for i := 0; i < len(userSlice); i++ {

		fmt.Println("Welcome to Slices, Please enter a number to add to the slice:")

		checkForX, _ := inputReader.ReadByte()

		if checkForX == 'X' {
			fmt.Println("Thanks for using Slices!")
			os.Exit(0)
		} else {

			userSlice[i] = int(checkForX - '0')
			fmt.Println("Slice so far:", userSlice)
		}

	}

} 

Here is the Output, I am not even attempting to add another value and yet it does on its own in the slice. I wonder why:

$ go run slices.go
Welcome to Slices, Please enter a number to add tothe slice:9
Slice so far: [9 0 0]
Welcome to Slices, Please enter a number to add tothe slice:
Slice so far: [9 218 0]
Welcome to Slices, Please enter a number to add tothe slice:X
Thanks for using Slices!

EDIT: Notice how nothing was typed the second time and then the second slot was filled in the slice for some reason. It’s odd

ReadByte reads a byte a value between 0 and 256. Then you write a 9 and presses newline will stdio contain these two bytes 57 (which is ‘9’) and 10 (which is ‘\n’ or newline). The first read will get 57 which you check for X and then subtracts with 48 (which is ‘0’) and then it will read another byte which is 10 and you will check it agains X and then subtract 48. Because bytes maximum value is 255 will 10 - 48 be -38 but it will just become 256 - 38 which is 218.

package main

import (
	"fmt"
)

func main() {
	var b byte = 0
	fmt.Println(b - 38)
}

will print 218

This is a bit hard to explain but I think you should try another approach which is reading string check it for X and else try to convert the string to an integer. Your program can’t handle numbers like 87 which will but the 8 and 7 as separate numbers.

@johandalabacka I completely understand your explanation. I think I will try something else. Thanks!

1 Like

Good luck and keep up the good work :slight_smile:

LOL more like keep up the bad work.

Nah, learning new stuff is hard.

I haven’t used the Scanner type, but Johan might have a good idea by suggesting that. It’s in the bufio package, and you can read about it there.

If you want to use ReadByte() or ReadBytes() it may be more complicated. You will need to read the bytes into a slice, and then later convert that into a string, and then you can convert that to an integer with strconv.Atoi().

Here is some code that will do the operations I described. First, some declarations.

    var intToAdd int
    var byteSlice []byte
    var i int

Now, to read the input,

byteSlice, _ = reader.ReadBytes('\n')

reads bytes from the input into byteSlice, including the newline.

if len(byteSlice) == 2 && byteSlice[0] == 'X' { os.Exit(0) }

exits if the 1st byte is an ‘X’. (To keep the example simple, I’m assuming there was no error and the 2nd byte is a ‘\n’.)

s := string(byteSlice[:len(byteSlice)-1]) 

convert the slice into a string. (Notice that I subtract 1 from the length to ignore the newline at the end, which would confuse strconv.Atoi())

intToAdd, _ = strconv.Atoi(s)

Convert the string into an integer.

if(i < 3) { userSlice[i] = intToAdd; i++ } else { userSlice = append(userSlice,intToAdd) }

I didn’t use append() for the first three because append() adds to the end of an existing slice. When you used make() to create the slice, the 3 elements were initialized to zero.

I checked to make sure all that worked by writing a program that solves the problem you were given. So if you want to try this method, it should work as I described. Or at least you can look it over and maybe learn from it.

2 Likes

@jayts, thank you! I will give that a try and report back here. Cheers!

I want to thank everyone thus far for the assistance. Based on the suggestions from @jayts and @johandalabacka, I have come a long way. Thanks!

I am having issues with the sort.Ints() function though as it semi-sorts but sometimes removes an integer from the slice. It just seems a bit odd. Index 0 seems to always be 0 in the sorted slice here is what the output looks like:

Assessment1 $ go run slices.goWelcome to Slices, Please enter a number to add tothe slice:1Slice so far: [0 0 1]
Welcome to Slices, Please enter a number to add tothe slice:9
Slice so far: [0 1 9]
Welcome to Slices, Please enter a number to add tothe slice:10
Slice so far: [0 1 10]
Welcome to Slices, Please enter a number to add tothe slice:12
Slice so far: [0 1 10 12]
Welcome to Slices, Please enter a number to add tothe slice:15
Slice so far: [0 1 10 12 15]
Welcome to Slices, Please enter a number to add tothe slice:X 

As one can see, 9 was omitted from the slice. Here is the code:

    // Write a program which prompts the user to enter integers and stores the integers in a sorted slice.
    // The program should be written as a loop. Before entering the loop, the program should create an empty
    // integer slice of size (length) 3. During each pass through the loop, the program prompts the user to enter an
    // integer to be added to the slice. The program adds the integer to the slice, sorts the slice, and prints
    // the contents of the slice in sorted order. The slice must grow in size to accommodate any number of integers
    // which the user decides to enter. The program should only quit (exiting the loop) when the user enters the
    // character ‘X’ instead of an integer.

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strconv"
)

func main() {
	userSlice := make([]int, 3) //Create a Slice of size 3

	inputReader := bufio.NewReader(os.Stdin)
	var intToAdd int
	var byteSlice []byte

	i := 0
	for i < 100 {

		fmt.Println("Welcome to Slices, Please enter a number to add to the slice:")

		byteSlice, _ = inputReader.ReadBytes('\n')

		if len(byteSlice) == 2 && byteSlice[0] == 'X' {
			os.Exit(0)
		} else {
			s := string(byteSlice[:len(byteSlice)-1])
			intToAdd, _ = strconv.Atoi(s)
			if i < 3 {
				userSlice[i] = intToAdd

			} else {
				userSlice = append(userSlice, intToAdd)
			}
			sort.Ints(userSlice)
			fmt.Println("Slice so far:", userSlice)
		}
		i++
	}

}

You’re making great progress. The reason why a number disappers is because then the slice is sorted changes the order but you still inserts values at a specifik index

[0, 0, 0] you enter 9 at index 0 [9, 0, 0] and slice is sorted [0, 0, 9]
[0, 0, 9] you enter 6 at index 1 [0, 6, 9] and slice is sorted [0, 6, 9]
[0, 6, 9] you enter 4 at index 2 [0, 6, 4] and slice is sorted [0, 4, 6] and here does the 9 disappear

You cant sort the whole array until it is completly filled. then i < 3 must you sort a slice of userslice like sort.Ints(userslice[x:y]) there both or one of x and y can be specified

1 Like

You are really close to solving it! As Johan said, the problem is that after you sort the slice and i is still less than 3, you may overwrite an element of the slice the next time you put another integer into it.

Here is one thing you can try: Don’t ever sort userSlice. When you want to print it in sorted order, use make() to make a new slice with the same number of elements, then use Go’s built-in copy() function to make the new slice into a copy of userSlice. Then sort and print the new slice.

(If you want to be efficient, you can use this method when i < 3, and use the way you are doing it now when i >= 3.)

I got that to work, but I won’t show you the code because I don’t want to spoil the exercise for you. If you haven’t learned about copy() yet, you can read about Go’s built-in functions here:

https://golang.org/src/builtin/builtin.go

Look for func copy(dst, src []Type) int in that page, and read the comment just above it that explains how copy() works. This might be a good time to look at information about the other built-in functions, too!

1 Like

@jayts and @johandalabacka thanks once again for the tremendous help. I am a bit dissapointed in myself for asking for help. Thanks!

No you shouldn’t be disappointed. Smart people asks for help and you managed to push so much further.

1 Like

I agree with Johan. Don’t feel bad about it at all!

Here’s a story for you from “ancient history”: I started learning C in 1981 when there was only one book in the world on the subject, and the the World Wide Web wasn’t even an idea. All I had was The C Programming Language (by Brian Kernighan and Dennis Ritchie, who both worked to develop Unix and C at Bell Labs), and there were parts of it I simply did not understand. I was having trouble with C because my previous experience with programming was with BASIC, Fortran, and a very odd language called APL (from which Go gets the iota constant thingy). I had absolutely no exposure to Algol or anything related to it. I liked C very much, but the ideas were strange to me.

I was really lucky I had a good friend who knew the language well already. I asked him a bunch of stupid questions that I’d be really embarrassed to have printed on the Internet today! I’m sure my dumb newbie questions amused him, and thankfully, he took the time to explain simple things to me. I went on to learn C really well, and up until recently, when I started learning Go, C was my favorite programming language. I’ve used it for all sorts of things for over 35 years and counting.

I hope you and others here on the forum who are just getting started with Go eventually learn Go as well as I learned C! I’m happy to spend some time answering simple questions because I still remember what it was like to need a little help getting started, and how valuable that help was to me.

1 Like

I know this topic is very old, but for a simpler approach to anybody who would visit here, I came up with this solution, keeping in mind about the exit when character is entered and the 0s in the slice. The problem is we cannot compare runes that identify as alias for int32 with the character runes (not a proper term but I hope you get the idea of it). When we enter a when the loop starts, and we enter an integer, and then a character, the rune would not accept that character, more like it skips is what I’ve noticed, so the integer value from the past remains the same. So resetting the value of the input rune at the beginning of every loop might solve this. But there would be a problem not being able to use that integer again in the slice. I’m sorry about that, but here it is, let me know if this helps :slight_smile:

package main

import (
	"fmt"
	"sort"
)

func main() {
	var ele rune
	var size int
	var sli = make([]int,0,3)
	size = cap(sli)
	for i:=0; i<=size; i++{
		if i>=len(sli){
			size=size+1
		}
		ele = 0
		fmt.Println("Enter a number to add: ")
		fmt.Scan(&ele)
		if ele==0 {
			fmt.Println("Stopping!")
			break
		}
		sli = append(sli, int(ele))
	}
	sort.Ints(sli)
	fmt.Println(sli)
}