2016-05-28 14 views
5

Ho dato una prova a HackerRank dove i problemi spesso richiedono la lettura di righe di interi in array (slice).Modo conciso e robusto per leggere una riga di interi separati da spazi in Go

Per molti dei problemi, il mio codice di analisi risulta essere più grande della carne algoritmica della soluzione. Ad esempio, è stato il caso in Sherlock and Array

Qualche idea su come analizzare in modo conciso una linea di numeri interi separati in una sezione? fmt.Scanf non supporta le slice e quando si utilizza bufio ottengo soluzioni lunghe.

Alcuni requisiti:

  • È possibile utilizzare solo la libreria standard.
  • La soluzione deve essere concisa, minore è, meglio è.
  • I controlli degli errori non devono essere saltati. So che l'input è ben definito in HackerRank e dovresti essere in grado di tagliare gli angoli, ma per favore non farlo, è una cattiva pratica.
  • Dovrebbe essere ragionevolmente efficiente.

NOTA: Il parser dovrebbe consumare solo una singola linea e non l'ingresso completo.

risposta

1

1) Leggere stringa

2) prepend [ e aggiungere ]

3) analizzare come JSON in [] 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) 
} 

anche mediante stringhe parziali (https://godoc.org/strings#Split) e 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: appena trovato che i numeri sono separate da spazi. Quindi, questo codice ha a che fare la cosa:

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) 
} 
+1

Nizza _abuse_ di JSON :) Tuttavia, le stringhe sono separati da spazi (non separato da virgole) e leggendo l'intera linea è piuttosto inefficiente nello spazio. – fons

1
// 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 
} 
+0

Non definirei questo conciso, in effetti sembra simile a ciò che ho scritto. – fons

+1

./shrug se vuoi piccole funzioni prova ruby ​​:) – Plato

+0

Oppure Python, o Haskell :) Vorrei usare go, ma fa schifo dedicare più tempo alla parte parsing che alla carne del problema. – fons

2

È possibile utilizzare fmt.Scanf, ma è necessario tenere traccia dei valori che stai ricevendo.

// 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} 
+0

Questa è l'opzione migliore finora. Non è necessario controllare n perché si otterrà sempre un errore se n! = 1 – fons

+0

In realtà, io rimango corretto, questo non funziona perché non dice separatamente EOL ed EOF, dovrebbe solo consumare una linea . – fons

+0

Si voleva _parse una linea ** separata dagli spazi ** di interi in una slice_. – noisypixy

0

Ho usato questo per quei tempi, che giocano in hackerrank (in modo conciso, ma non testato per gli esseri umani ):

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 
} 
3

Beh, ho ha fatto anche alcuni problemi con l'hacker, ed ecco cosa mi è venuto in mente. In genere, i problemi iniziano con il numero di elementi nella matrice:

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 
} 
Problemi correlati