In Go, scan numbers from a line using recursion - input

I want to scan a line of integers from stdin into a slice of integers. Each integer is separated by whitespace. Ther would be as many as N integers of user input. I'm trying not to use a for loop. For example,
1 15 16 17
So far, this is my function to perform the task,
var array []int
func read(b int) {
if b == 0 {
return
}
fmt.Scanf("%d", &array)
read(b - 1)
}
The idea is to read from the input, 1 15 16 17, and make it into a slice with value [1 15 16 17]
After compiling, I got the error,
Runtime error

For example,
package main
import "fmt"
var a []int
func read(b int) {
if b == 0 {
return
}
var i int
_, err := fmt.Scanf("%d", &i)
if err != nil {
return
}
a = append(a, i)
read(b - 1)
}
func main() {
read(4)
fmt.Println(a)
}
Input:
1 15 16 17<Enter>
Output:
[1 15 16 17]

Not recursive, but just reading integers until stdin is closed or something that can't be converted to an integer is read.
package main
import "fmt"
func main() {
var array []int
var i int
for {
_, err := fmt.Scan(&i)
if err != nil {
break
}
array = append(array, i)
fmt.Println("read number", i, "from stdin, array ", array)
}
}

Related

Reverse int golang

How to change 12345 to 54321?
With a string, you can change the string to a rune, and reverse it, but you cannot do the same for an integer. I have searched and found no one talking about this. Examples
131415 >>> 514131
1357 >>> 7531
123a >>> ERROR
-EDIT-
I was thinking, why not create a slice and index that?
Then I realized that you can't index int
(http://play.golang.org/p/SUSg04tZsc)
MY NEW QUESTION IS
How do you index an int?
OR
How do you reverse a int?
Here is a solution that does not use indexing an int
package main
import (
"fmt"
)
func reverse_int(n int) int {
new_int := 0
for n > 0 {
remainder := n % 10
new_int *= 10
new_int += remainder
n /= 10
}
return new_int
}
func main() {
fmt.Println(reverse_int(123456))
fmt.Println(reverse_int(100))
fmt.Println(reverse_int(1001))
fmt.Println(reverse_int(131415))
fmt.Println(reverse_int(1357))
}
Result:
654321
1
1001
514131
7531
Go playground
I converted the integer to a string, reverse the string, and convert the result back to a string.
package main
import (
"fmt"
"strconv"
)
func main() {
fmt.Println(reverse_int(123456))
fmt.Println(reverse_int(100))
fmt.Println(reverse_int(1001))
fmt.Println(reverse_int(131415))
fmt.Println(reverse_int(1357))
}
func reverse_int(value int) int {
intString := strconv.Itoa(value)
newString := ""
for x := len(intString); x > 0; x-- {
newString += string(intString[x - 1])
}
newInt, err := strconv.Atoi(newString)
if(err != nil){
fmt.Println("Error converting string to int")
}
return newInt
}
Very similar to the first answer but this checks to make sure you don't go out of bounds on the type.
func reverse(x int) int {
rev := 0
for x != 0 {
pop := x % 10
x /= 10
if rev > math.MaxInt32/10 || (rev == math.MaxInt32 /10 && pop > 7) {
return 0
}
if rev < math.MinInt32/10 || (rev == math.MinInt32/10 && pop < -8) {
return 0
}
rev = rev * 10 + pop
}
return rev
}
Also flips negative numbers int
func Abs(x int) int {
if x < 0 {
return -x
}
return x
}
func reverse_int(n int) int {
newInt := 0
sign := 1
if n < 0 {
sign = -1
}
n = Abs(n)
for n > 0 {
remainder := n % 10
newInt = newInt*10 + remainder
n /= 10
}
return newInt * sign
}
func main() {
fmt.Println(reverse_int(-100))
fmt.Println(reverse_int(-1001))
fmt.Println(reverse_int(131415))
fmt.Println(reverse_int(1357))
}
Similar to Fokiruna's answer but also checks for a 32bit overflow
func reverse(x int) int {
result, sign := 0, 1
if(x < 0) {
sign = -1
x = -x
}
for x > 0 {
remainder := x % 10;
result = result * 10 + remainder
x = x/10
}
var checkInt int = int(int32(result))
if checkInt != result {
return 0
}
return result * sign
}

Golang: int to slice conversion

Total golang (and programming) noob!
Given any six digit number, how could one output a slice where each character of that number is assigned an individual location within the slice?
For instance, a slice (let's call it s) containing all of these characters, would have s[0]=first digit, s[1]=second digit, s[2]=third digit and so on.
Any help would be greatly appreciated!
func IntToSlice(n int64, sequence []int64) []int64 {
if n != 0 {
i := n % 10
// sequence = append(sequence, i) // reverse order output
sequence = append([]int64{i}, sequence...)
return IntToSlice(n/10, sequence)
}
return sequence
}
The above answers are correct. Here comes another version of MBB's answer.
Avoiding recursion and efficient reverting may increase performance and reduce RAM consumption.
package main
import (
"fmt"
)
func reverseInt(s []int) {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
}
func splitToDigits(n int) []int{
var ret []int
for n !=0 {
ret = append(ret, n % 10)
n /= 10
}
reverseInt(ret)
return ret
}
func main() {
for _, n := range splitToDigits(12345) {
fmt.Println(n)
}
}
https://play.golang.org/p/M3aOUnNIbdv
This is a two step process, first converting int to string, then iterating the string or converting to a slice. Because the built in range function lets you iterate each character in a string, I recommend keeping it as a string. Something like this;
import "strconv"
str := strconv.Itoa(123456)
for i, v := range str {
fmt.Println(v) //prints each char's ASCII value on a newline
fmt.Printf("%c\n", v) // prints the character value
}
I'm confused why nobody mentioned this way:
(No need recursion)
import (
"fmt"
"strconv"
)
func main() {
n := 3456
fmt.Println(NumToArray(n))
fmt.Println(NumToArray2(n))
}
func NumToArray(num int) []int {
arr := make([]int, len(strconv.Itoa(num)))
for i := len(arr) - 1; num > 0; i-- {
arr[i] = num % 10
num = int(num / 10)
}
fmt.Println(arr)
return arr
}
// Without converting to string
func NumToArray2(num int) (arr []int) {
for num > 0 {
arr = append(arr, num%10)
num = int(num / 10)
}
// Reverse array to the rigtht order
for i, j := 0, len(arr)-1; i < j; i, j = i+1, j-1 {
arr[i], arr[j] = arr[j], arr[i]
}
fmt.Println(arr)
return arr
}
P.S. Benchmarks are welcome
For this problem you can convert your int value to string and after that you can use split function which is under strings library.I hope below code will work for you!
package main
import (
"fmt"
"strings"
"strconv"
)
func main() {
num:=10101
a:=strconv.Itoa(num)
res:=strings.Split(a,"")
fmt.Println("The value of res is",res)
fmt.Printf("The type of res is %T\n",res)
fmt.Println(res[0])
}
Output: The value of res is [1 0 1 0 1]
The type of res is []string 1

fmt.Scanln expected newline error

I'm trying to learn Go, but stuck with this one: http://ideone.com/hbCamr or http://ideone.com/OvRw7t
package main
import "fmt"
func main(){
var i int
var f float64
var s string
_, err := fmt.Scan(&i)
if err == nil {
fmt.Println("read 1 integer: ",i)
} else {
fmt.Println("Error: ",err)
}
_, err = fmt.Scan(&f)
if err == nil {
fmt.Println("read 1 float64: ",f)
} else {
fmt.Println("Error: ",err)
}
_, err = fmt.Scan(&s)
if err == nil {
fmt.Println("read 1 string: ",s)
} else {
fmt.Println("Error: ",err)
}
_, err = fmt.Scanln(&s)
if err == nil {
fmt.Println("read 1 line: ",s)
} else {
fmt.Println("Error: ",err)
}
}
for this input:
123
123.456
everybody loves ice cream
the output was:
read 1 integer: 123
read 1 float64: 123.456
read 1 string: everybody
Error: Scan: expected newline
is this the expected behavior? why doesn't it work like C++ getline? http://ideone.com/Wx8z5o
The answer is in the documentation of Scanln:
Scanln is similar to Scan, but stops scanning at a newline and after the final item there must be a newline or EOF.
Scan behaves as documented as well:
Scan scans text read from standard input, storing successive space-separated values into successive arguments. Newlines count as space. It returns the number of items successfully scanned. If that is less than the number of arguments, err will report why.
To conclude: Scan puts each word (a string separated by space) into a corresponding argument, treating newlines as space. Scanln does the same but treats newlines as a stop character, not parsing any further after that.
In case you want to read a line (\n at the end) use bufio.Reader and its ReadString method:
line, err := buffer.ReadString('\n')
As a workaround, you can implement your own fmt.Scanner:
package main
import "fmt"
type newline struct { tok string }
func (n *newline) Scan(state fmt.ScanState, verb rune) error {
tok, err := state.Token(false, func(r rune) bool {
return r != '\n'
})
if err != nil {
return err
}
if _, _, err := state.ReadRune(); err != nil {
if len(tok) == 0 {
panic(err)
}
}
n.tok = string(tok)
return nil
}
func main() {
var n newline
fmt.Scan(&n)
fmt.Println(n.tok)
}
https://golang.org/pkg/fmt#Scanner

How to write tests against user input in Go

How would I test against user input from fmt.Scan/Scanf/Scanln?
For example how could I test that the function input will accept "4 5\n" and "1 2 3 4\n" from STDIN and return n == 5 and array == [1, 2, 3, 4].
package main
import (
"fmt"
)
// input gets an array from the user.
func input() (m int, array []int) {
fmt.Print("Enter the size of the array, n, and the difference, m: ")
var n int
_, err := fmt.Scanf("%d %d", &n, &m)
if err != nil {
panic(err)
}
fmt.Print("Enter the array as a space seperated string: ")
array = make([]int, n)
for i := 0; i < n; i++ {
_, _ = fmt.Scan(&array[i])
}
return m, array
}
func main() {
m, array := input()
fmt.Println(m, array)
}
Here's a very rough draft to illustrate the principle.
program.go
package main
import (
"fmt"
"os"
)
// input gets an array from the user.
func input(in *os.File) (m int, array []int) {
if in == nil {
in = os.Stdin
}
fmt.Print("Enter the size of the array, n, and the difference, m: ")
var n int
_, err := fmt.Fscanf(in, "%d %d", &n, &m)
if err != nil {
panic(err)
}
fmt.Print("Enter the array as a space seperated string: ")
array = make([]int, n)
for i := 0; i < n; i++ {
_, _ = fmt.Fscan(in, &array[i])
}
return m, array
}
func main() {
m, array := input(nil)
fmt.Println(m, array)
}
program_test.go
package main
import (
"fmt"
"io"
"io/ioutil"
"os"
"testing"
)
func TestInput(t *testing.T) {
var (
n, m int
array []int
)
in, err := ioutil.TempFile("", "")
if err != nil {
t.Fatal(err)
}
defer in.Close()
_, err = io.WriteString(in, "4 5\n"+"1 2 3 4\n")
if err != nil {
t.Fatal(err)
}
_, err = in.Seek(0, os.SEEK_SET)
if err != nil {
t.Fatal(err)
}
n, array = input(in)
if n != 5 || fmt.Sprintf("%v", array) != fmt.Sprintf("%v", []int{1, 2, 3, 4}) {
t.Error("unexpected results:", n, m, array)
}
}
Output:
$ go test
ok command-line-arguments 0.010s
You can't. At least not so easily, such that, it would be worth the effort.

Creating a large csv file for testing file access

I want to create a 10 GB file that looks like:
prefix:username:timestamp, number
So an example is like:
login:jbill:2013/3/25, 1
I want to create a 10GB file, by creating random rows like the one above.
How could I do this in Go?
I can have an array of prefixes like:
login, logout, register
And also an array of usernames:
jbill, dkennedy
For example,
package main
import (
"bufio"
"fmt"
"math/rand"
"os"
"strconv"
"time"
)
func main() {
fileSize := int64(10e9) // 10GB
f, err := os.Create("/tmp/largefile")
if err != nil {
fmt.Println(err)
return
}
w := bufio.NewWriter(f)
prefixes := []string{"login", "logout", "register"}
names := []string{"jbill", "dkennedy"}
timeStart := time.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC)
timeDur := timeStart.AddDate(1, 0, 0).Sub(timeStart)
rand.Seed(time.Now().UnixNano())
size := int64(0)
for size < fileSize {
// prefix:username:timestamp, number
// login:jbill:2012/3/25, 1
prefix := prefixes[int(rand.Int31n(int32(len(prefixes))))]
name := names[int(rand.Int31n(int32(len(names))))]
time := timeStart.Add(time.Duration(rand.Int63n(int64(timeDur)))).Format("2006/1/2")
number := strconv.Itoa(int(rand.Int31n(100) + 1))
line := prefix + ":" + name + ":" + time + ", " + number + "\n"
n, err := w.WriteString(line)
if err != nil {
fmt.Println(n, err)
return
}
size += int64(len(line))
}
err = w.Flush()
if err != nil {
fmt.Println(err)
return
}
err = f.Close()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("Size:", size)
}
Output:
register:jbill:2012/8/24, 15
login:jbill:2012/10/7, 98
register:dkennedy:2012/8/29, 70
register:jbill:2012/6/1, 89
register:jbill:2012/5/24, 63
login:dkennedy:2012/3/29, 48
logout:jbill:2012/7/8, 93
logout:dkennedy:2012/1/12, 74
login:jbill:2012/4/12, 14
login:jbill:2012/2/5, 83
This is a naive approach (1GB):
package main
import (
"fmt"
"log"
"os"
)
func main() {
myfile, err := os.OpenFile("myfile", os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
log.Fatal(err)
}
defer myfile.Close()
var pos int
var line string
// sample: login:jbill:2013/3/25, 1
line = fmt.Sprintf("%s:%s:%s, %d\n", "login", "jbill", "2013/3/25", 1)
for pos < 1024*1024*1024 {
bytes, err := myfile.Write([]byte(line))
if err != nil {
log.Fatal(err)
}
pos = pos + bytes
}
}
which takes forever (1:16), because the output is not buffered. By adding bufio you can decrease the time dramatically
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
myfile, err := os.OpenFile("myfile", os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
log.Fatal(err)
}
defer myfile.Close()
mybufferedfile := bufio.NewWriter(myfile)
var pos int
var line string
// sample: login:jbill:2013/3/25, 1
line = fmt.Sprintf("%s:%s:%s, %d\n", "login", "jbill", "2013/3/25", 1)
for pos < 1024*1024*1024 {
bytes, err := mybufferedfile.WriteString(line)
if err != nil {
log.Fatal(err)
}
pos = pos + bytes
}
err = mybufferedfile.Flush()
if err != nil {
log.Fatal(err)
}
}
Still 26 sec on my machine, I'd like to see a faster solution.
BTW: you need to do the random fileds, but that is left as an exercise to the reader :)