Home > Mobile >  Filtering nested array of structs
Filtering nested array of structs

Time:06-07

I have a function that returns an array of Result, I would like to create another function that takes []Results as input and should return []Results as output. this function should filter students based on Average lets say only student who have a average above 80 should be appended to filtered list how can I achieve this in go?

type Result struct {
    StudentName    string
    StudentNum         int
    Info     []StudentData
}

type StudentData struct {
    Name     string
    Age      int
    Report  *ReportCard
}

type ReportCard struct {
    Subject     string
    Average     float64
}

CodePudding user response:

I made a slight change to the structure.

For me, this question should be Filter the desired students according to the specified criteria.


I don't advocate hard coding of filter functions. I think the filtering conditions are very flexible, so I think the following method is more appropriate.

func NewFilter(sData []*Student, criteriaFunc func(subjects []*Subject) bool) func() []*Student {
    return func() []*Student {
        result := make([]*Student, 0)
        for _, curStudent := range sData {
            if criteriaFunc(curStudent.Report) {
                result = append(result, curStudent)
            }
        }
        return result
    }
}

Full Example

package main

import (
    "encoding/json"
    "fmt"
)

type Student struct {
    Name   string
    Age    int
    Report []*Subject
}

func (s Student) String() string {
    return fmt.Sprintf("%s(%d):% v", s.Name, s.Age, s.Report)
}

type Subject struct {
    Name    string `json:"Subject"`
    Average float64
}

func (s *Subject) String() string {
    return fmt.Sprintf("%s:%f", s.Name, s.Average)
}

const DBData string = `
{
  "Students": [
    {
      "Name": "Carson",
      "Age": 30,
      "Report": [
        {
          "Subject": "Math",
          "Average": 100
        },
        {
          "Subject": "English",
          "Average": 60
        }
      ]
    },
    {
      "Name": "Foo",
      "Age": 18,
      "Report": [
        {
          "Subject": "Math",
          "Average": 60
        },
        {
          "Subject": "English",
          "Average": 88
        }
      ]
    },
    {
      "Name": "Bar",
      "Age": 13,
      "Report": [
        {
          "Subject": "Math",
          "Average": 91.3
        },
        {
          "Subject": "English",
          "Average": 80.5
        }
      ]
    },
    {
      "Name": "Mary",
      "Age": 10,
      "Report": [
        {
          "Subject": "Math",
          "Average": 95.3
        },
        {
          "Subject": "English",
          "Average": 80.5
        }
      ]
    }
  ]
}
`

func NewFilter(sData []*Student, criteriaFunc func(subjects []*Subject) bool) func() []*Student {
    return func() []*Student {
        result := make([]*Student, 0)
        for _, curStudent := range sData {
            if criteriaFunc(curStudent.Report) {
                result = append(result, curStudent)
            }
        }
        return result
    }
}

func main() {
    var jsonObj struct {
        Students []*Student
    }
    if err := json.Unmarshal([]byte(DBData), &jsonObj); err != nil {
        panic(err)
    }

    students := jsonObj.Students

    filterMathExcellent := NewFilter(students, func(subjects []*Subject) bool {
        for _, s := range subjects {
            if s.Name == "Math" && s.Average > 90 {
                return true
            }
        }
        return false
    })

    // each subject score must >= 80
    filterEveryGood := NewFilter(students, func(subjects []*Subject) bool {
        for _, s := range subjects {
            if s.Average < 80 {
                return false
            }
        }
        return true
    })

    groupMathExcellentStudents := filterMathExcellent()
    groupEveryGoodStudents := filterEveryGood()
    fmt.Printf("% v\n", groupMathExcellentStudents)
    fmt.Printf("% v\n", groupEveryGoodStudents)
}

go playground

CodePudding user response:

package main

import "fmt"

type Result struct {
    StudentName string
    StudentNum  int
    Info        []StudentData
}

type StudentData struct {
    Name   string
    Age    int
    Report ReportCard
}

type ReportCard struct {
    Subject string
    Average float64
}

func main() {
    // Create a new Result struct
    result := []Result{
        {StudentName: "John", StudentNum: 1, Info: []StudentData{{Name: "John", Age: 20, Report: ReportCard{Subject: "Math", Average: 90}}}},
        {StudentName: "Jane", StudentNum: 2, Info: []StudentData{{Name: "Jane", Age: 21, Report: ReportCard{Subject: "English", Average: 80}}}},
        {StudentName: "Jack", StudentNum: 3, Info: []StudentData{{Name: "Jack", Age: 22, Report: ReportCard{Subject: "Science", Average: 70}}}},
        {StudentName: "Jill", StudentNum: 4, Info: []StudentData{{Name: "Jill", Age: 23, Report: ReportCard{Subject: "History", Average: 60}}}},
        {StudentName: "Joe", StudentNum: 5, Info: []StudentData{{Name: "Joe", Age: 24, Report: ReportCard{Subject: "Math", Average: 90}}}},
    }

    // filter the reesult to only include students with average of >= 80
    result = filter(result, 80)
    fmt.Println(result)
}

func filter(result []Result, average float64) []Result {
    var filtered []Result
    for _, r := range result {
        for _, s := range r.Info {
            if s.Report.Average >= average {
                filtered = append(filtered, r)
            }
        }
    }
    return filtered
}
  • Related