Reputation: 589
I'm new to SwiftUI and I've been stuck on this for a few days.
I have an unordered array that is identifiable. I have a filter for that array in the parent view and the value of the filter gets passed down the child view.
I'm needing to group elements based on a value of one element in the array, then calculate the total, subtotals, and average based on another value set in each array element.
The calculation needs to update based on the filter being set to true or false in the parent view.
I solved this easily in JavaScript (React) by making the calculations inside the ForEach view but don't know how to solve this in SwitUI.
Any help at all is greatly appreciated!
struct Student: Identifiable {
let id: String
let name: String
let gradeLevel: Int
let studyHours: Int
}
class GetStudents: ObservableObject {
@Published var items = [Student]()
init() {
self.items = [
Student(id: "aa1", name: "Bobby", gradeLevel: 9, studyHours: 2),
Student(id: "aa2", name: "Sally", gradeLevel: 12, studyHours: 4),
Student(id: "aa3", name: "Susy", gradeLevel: 11, studyHours: 3),
Student(id: "aa4", name: "Billy", gradeLevel: 12, studyHours: 5),
Student(id: "aa5", name: "Jimmy", gradeLevel: 11, studyHours: 1),
Student(id: "aa6", name: "Johnny", gradeLevel: 10, studyHours: 3),
Student(id: "aa7", name: "Mikey", gradeLevel: 12, studyHours: 2),
]
}
}
struct StudyTotals: View {
@ObservedObject var students = GetStudents()
var onlyUpperClass: Bool
var studentsFiltered: [Student] {
switch self.onlyUpperClass {
case true: return students.items.filter {$0.gradeLevel == 11 || $0.gradeLevel == 12 }
case false: return students.items
}
}
var body: some View {
var myArray = getCalcTotals(students: studentsFiltered)
var rows: Array<String> = []
return VStack {
Text("Push Calculated Rows Here??? ")
}.padding()
}
}
struct ContentView: View {
@State private var onlyUpperClass: Bool = false
var body: some View {
return VStack {
StudyTotals(onlyUpperClass: self.onlyUpperClass)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
func getCalcTotals(students: Array<Student>) -> Array<String> {
let studentArray = students.reduce({ /* here */ })
var grade: String
var gradeCount: Int
var gradeHours: Double? = 0
var gradeAvg: Double? = 0
let myArray = ["Count", "Total", "Average"]
return myArray
}
What I'm needing is this:
Upvotes: 2
Views: 1452
Reputation: 7656
You can calculate the values inside ForEach
as in JavaScript
struct StudyTotals: View {
@ObservedObject var students = GetStudents()
var onlyUpperClass: Bool
var studentsFiltered: [Student] {
switch self.onlyUpperClass {
case true: return students.items.filter {$0.gradeLevel == 11 || $0.gradeLevel == 12 }
case false: return students.items
}
}
var body: some View {
var countTotal = self.studentsFiltered.count
var hoursTotal = self.studentsFiltered.reduce(0) { $0 + $1.studyHours }
return List {
Group {
HStack {
Text("Count")
Text("Hours")
Text("Avg")
}
ForEach(9...12, id: \.self) { gradeLevel -> AnyView in
let count = self.studentsFiltered.filter{ $0.gradeLevel == gradeLevel }.count
let hours = self.studentsFiltered.filter{ $0.gradeLevel == gradeLevel }.reduce(0) { $0 + $1.studyHours }
let avg = Float(hours) / Float(count)
countTotal += count
hoursTotal += hours
return AnyView(HStack {
Text("Grade\(gradeLevel)")
Text("\(count)")
Text("\(hours)")
Text("\(avg)")
})
}
HStack {
Text("TOTALS")
Text("\(countTotal)")
Text("\(hoursTotal)")
Text("\(Float(hoursTotal) / Float(countTotal))")
}
}
}.padding()
}
}
Upvotes: 2