loop through slices and amend into a 2D array

I have 17 (len(inputStartSlice)) slices of indexes that'll make a series of string slices. Currently, my code is only producing a single slice of strings (a single input, as I hardcode the positions, seen below) when I have 17 that I need to loop through into a single, 2D array of strings.

var inputSlices []string
var inputStartSlice []int
var inputEndSlice []int
var input []string
var inputs [][]string


for v, line := range inputSlices {
  if strings.Contains(line, "{") {
    inputStartSlice = append(inputStartSlice, v)
  }
  if strings.Contains(line, "}") {
    inputEndSlice = append(inputEndSlice, v+1)
  }
}

input = inputSlice[inputStartSlice[3]:inputEndSlice[3]]

inputs = append(inputs, input)
fmt.Println(inouts)

Playground

Is there a better way to go about doing this? I'm sure there is, if anybody can help me understand better approaches or elaborate on how I can solve where I'm currently stuck..

2 answers

  • answered 2022-05-05 08:10 Fenistil

    I've rewritten your code in a more idiomatic way. Check the comments for explanations. This code works, but as mpx suggested, for processing any custom format you have to write a tokenizer and a lexer to be sure that everything is parsed correctly and every possible syntax error is handled.

    package main
    
    import (
        "fmt"
        "log"
        "strings"
    
        "golang.org/x/exp/slices"
    )
    
    func main() {
    
        var codeSlices = []string{
            "# INPUTS",
            "",
            "input CreateUserInput {",
            "  username: String!",
            "  email: String!",
            "  password: String!",
            "}",
            "",
            "input AuthUserInput {",
            "  user: String!",
            "  password: String!",
            "  code: String",
            "}",
            "",
            "input RefreshTokensInput{",
            "  refreshToken: String!",
            "}",
            "",
            "input VerifyEmailInput {",
            "  token: String!",
            "}",
            "",
            "# OBJECTS",
            "",
        }
    
        //Check for boundaries
        inputStart := slices.Index(codeSlices, "# INPUTS") //Use built-in functions for the search
        if inputStart == -1 {
            log.Fatal("# INPUTS not found")
        }
    
        objectStart := slices.Index(codeSlices, "# OBJECTS")
        if objectStart == -1 {
            log.Fatal("# OBJECTS not found")
        }
    
        var inputStartSlice []int
        var inputEndSlice []int
    
        //No need to copy your codeSlices to inputSlice, just go from inputs to objects, this is faster.
        for i := inputStart + 2; i < objectStart-1; i++ {
            if strings.HasSuffix(codeSlices[i], "{") { //HasSuffix is better here, since the { must be the last char
                inputStartSlice = append(inputStartSlice, i)
                continue //No need to check for closing bracket, so we can continue to skip another check
            }
            if codeSlices[i] == "}" { //Direct equality is faster than Contains
                inputEndSlice = append(inputEndSlice, i+1)
            }
        }
    
        //Check to every open bracket have a closing one
        if len(inputStartSlice) != len(inputEndSlice) {
            log.Fatal("len(inputStartSlice) != len(inputEndSlice)")
        }
    
        //Concating final results
        var inputs [][]string
        for i := range inputStartSlice {
            inputs = append(inputs, codeSlices[inputStartSlice[i]:inputEndSlice[i]])
        }
    
        fmt.Println(inputs)
    }
    

  • answered 2022-05-05 09:02 Chandan

    You can achieve the same without using extra variables

    package main
    
    import (
        "fmt"
        "log"
        "strings"
    
        "golang.org/x/exp/slices"
    )
    
    func main() {
    
        var codeSlices = []string{
            "# INPUTS",
            "",
            "input CreateUserInput {",
            "  username: String!",
            "  email: String!",
            "  password: String!",
            "}",
            "",
            "input AuthUserInput {",
            "  user: String!",
            "  password: String!",
            "  code: String",
            "}",
            "",
            "input RefreshTokensInput{",
            "  refreshToken: String!",
            "}",
            "",
            "input VerifyEmailInput {",
            "  token: String!",
            "}",
            "",
            "# OBJECTS",
            "",
        }
    
        //Check for boundaries
        inputStart := slices.Index(codeSlices, "# INPUTS") //Use built-in functions for the search
        if inputStart == -1 {
            log.Fatal("# INPUTS not found")
        }
    
        objectStart := slices.Index(codeSlices, "# OBJECTS")
        if objectStart == -1 {
            log.Fatal("# OBJECTS not found")
        }
    
        inputStart = 0
        var inputs [][]string
        for i := inputStart + 2; i < objectStart-1; i++ {
            if idx := strings.Index(codeSlices[i], "{"); idx > 0 {
                inputStart = i
                continue
            }
            if idx := slices.Index(codeSlices[inputStart:], "}"); inputStart > 0 {
                inputs = append(inputs, codeSlices[inputStart:i+idx])
                inputStart = 0
            }
        }
    
        if inputStart > 0 {
            log.Fatal("Mismatch inputs")
        }
    
        fmt.Printf("%#v\n", inputs)
    }
    

    Playground

How many English words
do you know?
Test your English vocabulary size, and measure
how many words do you know
Online Test
Powered by Examplum