Search code examples
arraysgomappingslice

GoLang - looping through array of structs - can I map?


I'm new to GoLang, coming from Node. A little late to the (definitely not functional) game and need some help understanding approaches, and perhaps just understanding...

I want to omit an item from a bunch of structs in an array.

lo.Map(twelveShuffledQuestions, func(q StaticQuestion) {
        return &StaticQuestionMinusCorrectAnswer{
            QuestionId:       q.QuestionId,
            QuestionType:     q.QuestionType,
            QuestionText:     q.QuestionText,
            PotentialAnswers: q.PotentialAnswers,
            Image:            q.Image,
        }
    })

All this is basically doing is showing a pattern how I would go about it in node (with the help of lo) - and no, this isn't compiling as it cant infer the type args.

In terms of the data structure here, twelveShuffledQuestions is JSON backed, meaning it was imported and then marshalled:

jsonFile, err := os.Open("questions.json")
if err != nil {
    panic(err)
}
defer jsonFile.Close()
byteValue, _ := io.ReadAll(jsonFile)
localQuestionsToCheckAgainst := []StaticQuestion{}
json.Unmarshal([]byte(byteValue), &localQuestionsToCheckAgainst)

My question is how do I achieve this mapping of fields I want from the structs in the array?


Solution

  • Loop over the original questions. Create a question without answer and append to the result.

    byteValue, err := os.ReadFile("questions.json")
    if err != nil { panic(err) }
    var localQuestionsToCheckAgainst []*StaticQuestion
    json.Unmarshal(byteValue, &localQuestionsToCheckAgainst)
    var result []*StaticQuestionMinusCorrectAnswer
    for _, q := range localQuestionsToCheckAgainst {
        result = append(result, &StaticQuestionMinusCorrectAnswer{
            QuestionId:       q.QuestionId,
            QuestionType:     q.QuestionType,
            QuestionText:     q.QuestionText,
            PotentialAnswers: q.PotentialAnswers,
            Image:             q.Image,
        })
    }
    

    Here's how to use the lo package:

    byteValue, err := os.ReadFile("questions.json")
    if err != nil { panic(err) }
    var localQuestionsToCheckAgainst []*StaticQuestion
    json.Unmarshal(byteValue, &localQuestionsToCheckAgainst)
    result := lo.Map(localQuestionsToCheckAgainst, func(q *StaticQuestion, i int) *StaticQuestionMinusCorrectAnswer {
        return &StaticQuestionMinusCorrectAnswer{
            QuestionId:       q.QuestionId,
            QuestionType:     q.QuestionType,
            QuestionText:     q.QuestionText,
            PotentialAnswers: q.PotentialAnswers,
            Image:            q.Image,
        }
    })
    

    A for loop with range clause (the first snippet in this answer) is the idiomatic way to write the code. The upcoming range function feature makes for loops the preferred way to write most iteration code.