fons
fons

Reputation: 5137

Concise and robust way to read a line of space-separated integers in Go

I have been giving HackerRank a try where the problems often require reading lines of integers into arrays (slices).

For many of the problems, my parsing code ends up being larger than the algorithmic meat of the solution. For instance, that was the case in Sherlock and Array

Any ideas on how to concisely parse a space-separated line of integers into a slice? fmt.Scanf doesn't support slices and when using bufio I get long solutions.

Some requirements:

NOTE: The parser should only consume a single line and not the full input.

Upvotes: 7

Views: 4080

Answers (6)

Alishan Ahmed
Alishan Ahmed

Reputation: 21

func main() {
    arr := make([]int, 0)

    reader := bufio.NewReaderSize(os.Stdin, 1024*1024)

    for {
        line, _, err := reader.ReadLine()
        if err != nil {
          if err == io.EOF {
            break
          }
          panic(err)
        }


        str := strings.Split(string(line), " ")

        for i:=0; i<len(str); i++ {
            v, _ := strconv.Atoi(str[i])
            arr = append(arr, v)
        }
    }
    fmt.Println(arr)
}

Upvotes: 1

vodolaz095
vodolaz095

Reputation: 6986

1) read string

2) prepend [ and append ]

3) parse as json into []int?

var input = "1,2,3"
var answer []int
j := []byte(fmt.Sprintf("[%s]",input))
err:= json.Unmarshal(j, &input)
if err != nil {
  panic(err)
}
for k,v := range input {
   fmt.Printf("Element №%v is %v\n", k,v)
}

also using split strings (https://godoc.org/strings#Split) and https://godoc.org/strconv#ParseInt

input:= "1,2,3"
temp := strings.Split(input, ",")
var answer []int

for _,v := range temp {
  i,err := strconv.ParseInt(v)
  if err != nill {
     panic(err)
  }
  answer = append(answer, i)
}

UPD: just found that the numbers are SPACE separated. So, this code have to do the thing:

input:= "1 2 3"
temp := strings.Split(input, " ")
var answer []int

for _,v := range temp {
  i,err := strconv.ParseInt(v)
  if err != nill {
     panic(err)
  }
  answer = append(answer, i)
}

Upvotes: 1

Kaveh Shahbazian
Kaveh Shahbazian

Reputation: 13513

I've used this for those times playing in hackerrank (so concise, but not tested for humans):

func scanInt(n int) []int {
    input := make([]int, n)
    buffer := make([]interface{}, n)

    for i := 0; i < n; i++ {
        buffer[i] = &input[i]
    }

    fmt.Scanln(buffer...)

    return input
}

Upvotes: 0

T. Claverie
T. Claverie

Reputation: 12246

Well, I have done some hackerrank problems too, and here is what I came up with. Typically, problems start with the number of items in the array:

func main() {
    var N int
    fmt.Scanf("%d", &N)
    line := make([]int, N)
    for i, _ := range line {
        fmt.Scanf("%d", &line[i])
    }

    // Do something with the values
}

Upvotes: 4

noisypixy
noisypixy

Reputation: 774

You can use fmt.Scanf, but you need to keep track of the values you're getting.

// a.go
package main

import (
    "fmt"
    "io"
)

func main() {
    var (
        next int
        nums []int
    )

    for {
        n, err := fmt.Scanf("%d", &next)
        if err == io.EOF {
            break
        }
        if err != nil {
            panic(err)
        }
        if n == 0 {
            break
        }

        nums = append(nums, next)
    }

    fmt.Printf("%#v\n", nums)
}

$ echo "4 8 15 16 23 42" | go run a.go
[]int{4, 8, 15, 16, 23, 42}

Upvotes: 2

Plato
Plato

Reputation: 11052

// inputs space separated list of integers, outputs []int64
package main

import (
    "bufio"
    "fmt"
    "strconv"
    "strings"
)

func main() {
    fmt.Println(parse("100 200 300"))
}

func parse(i string) (o []int64) {
    // from https://golang.org/pkg/bufio/#example_Scanner_custom
    s := bufio.NewScanner(strings.NewReader(i))
    splitter := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
        advance, token, err = bufio.ScanWords(data, atEOF)
        if err == nil && token != nil {
            x, err := strconv.ParseInt(string(token), 10, 32)
            if err != nil {
                panic(err)
            }
            o = append(o, x)
        }
        return
    }
    s.Split(splitter)
    for s.Scan() {
    }
    return o
}

Upvotes: 2

Related Questions