Creating a dynamic 5X5 Matrix

Hey guys, so i am making like a quiz app. each question in the app has 2 answers which are chosen from separate pickers.

import Foundation import SwiftUI import UIKit import PDFKit

struct MatrixViewControllerWrapper: UIViewControllerRepresentable { func makeUIViewController(context: Context) -> MatrixViewController { return MatrixViewController() }

func updateUIViewController(_ uiViewController: MatrixViewController, context: Context) {
    // Update the view controller if needed
}

}

struct ReinforedSlopeFormView: View { // Environment variable for managing presentation mode @Environment(.presentationMode) var presentationMode

// Form input state variables

@State private var settlementPickerIndex = 0
@State private var displacementPickerIndex = 0
@State private var riskIndexPickerIndex1 = 0
@State private var riskIndexPickerIndex2 = 0

let matrixLabelSize: CGFloat = 30.0 let numberOfRows = 5

var body: some View {
    NavigationView {
        Form {
            Group {
                // Settlement Section
                Section(header: Text("Settlement").font(.title3).bold() ) {
                    Picker("Criteria", selection: $settlementPickerIndex, content: {
                        ForEach(0..<ReinforcedQData().settlementChoices.count, id: \.self) { index in
                            Text(ReinforcedQData().settlementChoices[index])
                        }
                    })
                    .pickerStyle(MenuPickerStyle())

                    Picker("Relative Risk", selection: $riskIndexPickerIndex1, content: {
                        ForEach(0..<ReinforcedQData().riskIndexChoices.count, id: \.self) { index in
                            Text(ReinforcedQData().riskIndexChoices[index])
                        }
                    })
                    .pickerStyle(MenuPickerStyle())
                    
                    Text("Score: \(ReinforcedQData().settlementScores[settlementPickerIndex]), \(ReinforcedQData().riskIndexScores[riskIndexPickerIndex1])")
                }
                //Slope Angle - Bedrock
                Section(header: Text("Horizontal Displacement").font(.title3).bold() ) {
                    Picker("Criteria", selection: $displacementPickerIndex, content: {
                        ForEach(0..<ReinforcedQData().displacementChoices.count, id: \.self) { index in
                            Text(ReinforcedQData().displacementChoices[index])
                        }
                    })
                    .pickerStyle(MenuPickerStyle())

                    
                    Picker("Relative Risk", selection: $riskIndexPickerIndex2, content: {
                        ForEach(0..<ReinforcedQData().riskIndexChoices.count, id: \.self) { index in
                            Text(ReinforcedQData().riskIndexChoices[index])
                        }
                    })
                    .pickerStyle(MenuPickerStyle())
                    
                    Text("Score: \(ReinforcedQData().displacementScores[displacementPickerIndex]), \(ReinforcedQData().riskIndexScores[riskIndexPickerIndex2])")
                }}
    }
}

there are more 19 more sections making 21 questions for this code. below each section has a text printed as Score: (A,B) where A and B here are numbers making it look like coordinates. the picker index values and choices are created in a separate file.

can anyone help me in creating a matrix with those scores as the coordinates?

i have this existing matrix code in a separate swift file:

import SwiftUI import UIKit

class MatrixViewController: UIViewController {

let matrix = [
    ["A5", "B5", "C5", "D5", "E5"],
    ["A4", "B4", "C4", "D4", "E4"],
    ["A3", "B3", "C3", "D3", "E3"],
    ["A2", "B2", "C2", "D2", "E2"],
    ["A1", "B1", "C1", "D1", "E1"],
]

let matrixLabelSize: CGFloat = 30.0

override func viewDidLoad() {
    super.viewDidLoad()
    
    setupMatrixView()
}

func setupMatrixView() { . . . }

struct Coordinate {
    let row: Int
    let column: Int
    let value: String
}

// Define the coordinate values
@State var coordinates = [
    Coordinate(row: 1, column: 1, value: "A"),
    Coordinate(row: 1, column: 2, value: "B")]

struct MatrixViewControllerPreview: UIViewControllerRepresentable {
    
    func makeUIViewController(context: Context) -> UIViewController {
        return MatrixViewController()
    }
    
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
        
    }
}

How can i set up the coordinates here when it the score variable represents the score obtained from the user's choices. It is split into separate values using the comma as a separator. The extracted values are then used to create a new Coordinate object, which is appended to the coordinates array. i am unsure of how the code should be.

also when for example there are 2 values of the same coordinates, it should show 2 in that coordinate in the matrix view. if there are none, the initial value of each coordinate will be zero.

Your input is greatly appreciated.

Thank you! Best regards!

--from a person who just started learning

Hi! I didn’t really understand the things that you want to store in your matrix, could you please explain that better? Why do you need 5 dimensions?

I feel like using such a matrix for storing data is not a good idea and might not be easy to work with. You might be interested in learning more about Object Oriented Programming (OOP), and maybe store each question’s data inside a struct or a class that would represent a question.

the matrix I want to make actually is part of the main output in this app. It is basically a risk matrix, where the x-axis is the severity and the y-axis is the likelihood.

i need it to be 5x5 because it corresponds to: X-axis = level of severity (Negligible (1), Minor(2) , Moderate(3), Significant(4) and Major(5) Y-axis = levels of likelihood (1, 2, 3, 4, 5)

now these values are chosen by the users from a set of answers. So let's say one question is: Q: Estimate uncertainty A1 (severity) : users choose an answer between negligible to major) A2 (likelihood): users choose an answer between 1-5

there are at least 21 questions all must be answered by likelihood and severity

now these answers should correspond as a coordinate into the matrix. so if they answer Q1: (1,3) Q2: (1,5) Q3: (1,5) Q4: (1,1) and so on..

so there may be coordinates in the matrix that have more than 1 value

so if there are 2 of the same coordinates, it should show 2 in the matrix view.

this is the output of the app. the answers as well as the matrix will be placed into a pdf to be exported as a document.

i hope this clears the purpose of the matrix

From what I've understood, it doesn't need to be 5 dimensional, but rather, 2 dimensional.

The dimension in a matrix doesn't correspond to the number of rows and columns. In your case, two dimensions seems enough: one for the severity (from one to five), and one for the likelihood (1 to 5).

You could therefore store data like so :

Matrix[2][5] = 3 (which would mean that there are 3 questions that have a severity of 2 and a likelihood of 3).

A good visual representation of the dimensions of a matrix would be the following. A one-dimensional matrix is just an array/list. A two dimensional array corresponds to an Excel/Numbers spreadsheet. And a three dimensional array could be use to store the coordinates of the cubes composing a Rubik's Cube, for example. Above 3, it's hard to have a visual representation.

A 5-dimensional matrix would be suitable if you had 5 different sliders per question.

Therefore, if you can represent your table in a spreadsheet, it means that two dimensions is enough.

Let me know if my answer is suitable for your project! :)

i need it to be 5x5 because it corresponds to: X-axis = level of severity (Negligible (1), Minor(2) , Moderate(3), Significant(4) and Major(5) Y-axis = levels of likelihood (1, 2, 3, 4, 5)

No, as louis-carbo explained, you need a 2 dimension matrix.

just a correction, as arrays start at 0:

Matrix[1][4] = 3 // (which would mean that there are 3 questions that have a severity of 2 and a likelihood of 5).

In your matrix:

let matrix = [
    ["A5", "B5", "C5", "D5", "E5"],
    ["A4", "B4", "C4", "D4", "E4"],
    ["A3", "B3", "C3", "D3", "E3"],
    ["A2", "B2", "C2", "D2", "E2"],
    ["A1", "B1", "C1", "D1", "E1"],
]
matrix[1] is ["A4", "B4", "C4", "D4", "E4"]

so matrix[1][3] is  "D4"

import SwiftUI import UIKit

class MatrixViewController: UIViewController {

let matrix = [
    ["A5", "B5", "C5", "D5", "E5"],
    ["A4", "B4", "C4", "D4", "E4"],
    ["A3", "B3", "C3", "D3", "E3"],
    ["A2", "B2", "C2", "D2", "E2"],
    ["A1", "B1", "C1", "D1", "E1"],
]

let matrixLabelSize: CGFloat = 30.0

override func viewDidLoad() {
    super.viewDidLoad()
    
    setupMatrixView()
}

func setupMatrixView() {
    let matrixView = UIView()
    matrixView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(matrixView)

    let matrixViewWidth = CGFloat(matrix[0].count) * matrixLabelSize
    let matrixViewHeight = CGFloat(matrix.count) * matrixLabelSize


    NSLayoutConstraint.activate([
        matrixView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        matrixView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
        matrixView.widthAnchor.constraint(equalToConstant: matrixViewWidth),
        matrixView.heightAnchor.constraint(equalToConstant: matrixViewHeight)
    ])


    var positionCounts: [String: Int] = [:]

    //counting the number of occurences - - - - - -  this part
    for coordinate in coordinates {
        let row = coordinate.row
        let column = coordinate.column

        // Update the count for the position
        let key = "\(row)\(column)"
        positionCounts[key, default: 0] += 1
    }

    
    for rowIndex in 0..<matrix.count {
        for colIndex in 0..<matrix[rowIndex].count {
            let label = UILabel()
            label.translatesAutoresizingMaskIntoConstraints = false
            label.textAlignment = .center
            label.backgroundColor = .white
            label.layer.borderColor = UIColor.black.cgColor
            label.layer.borderWidth = 1.0

            // Get the count from the dictionary based on the position
            let key = "\(rowIndex + 1)\(colIndex + 1)"
            let count = positionCounts[key, default: 0]
            label.text = "\(count)"

            matrixView.addSubview(label)

            NSLayoutConstraint.activate([
                label.leadingAnchor.constraint(equalTo: matrixView.leadingAnchor, constant: CGFloat(colIndex) * matrixLabelSize),
                label.topAnchor.constraint(equalTo: matrixView.topAnchor, constant: CGFloat(rowIndex) * matrixLabelSize),
                label.widthAnchor.constraint(equalToConstant: matrixLabelSize),
                label.heightAnchor.constraint(equalToConstant: matrixLabelSize)
            ])

        }
    }
}

struct Coordinate {
    let row: Int
    let column: Int
    let value: String
}

// Define the coordinate values - - - - -  THESE COORDINATE VALUES. i want this values to come from the users input 
@State var coordinates = [
    Coordinate(row: 1, column: 1, value: "A"),
    Coordinate(row: 1, column: 1, value: "B"),
    Coordinate(row: 1, column: 4, value: "C"),
    Coordinate(row: 2, column: 4, value: "D"),
    Coordinate(row: 4, column: 4, value: "E"),
    Coordinate(row: 3, column: 4, value: "A"),
    Coordinate(row: 3, column: 3, value: "B"),
    Coordinate(row: 4, column: 3, value: "C"),
    Coordinate(row: 4, column: 4, value: "D"),
    Coordinate(row: 4, column: 4, value: "E"),
    Coordinate(row: 1, column: 4, value: "A"),
    Coordinate(row: 2, column: 1, value: "B"),
    Coordinate(row: 2, column: 2, value: "C"),
    Coordinate(row: 1, column: 2, value: "D"),
    Coordinate(row: 1, column: 3, value: "E"),
    Coordinate(row: 5, column: 2, value: "A"),
    Coordinate(row: 1, column: 5, value: "B"),
    Coordinate(row: 1, column: 5, value: "C"),
    Coordinate(row: 5, column: 3, value: "D"),
    Coordinate(row: 1, column: 4, value: "E"),
    Coordinate(row: 5, column: 2, value: "A"),

]

@available(iOS 13.0, *)
struct MatrixViewControllerPreview: UIViewControllerRepresentable {
    
    func makeUIViewController(context: Context) -> UIViewController {
        return MatrixViewController()
    }
    
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
        
    }
}

@available(iOS 13.0, *)
struct MatrixViewController_Previews: PreviewProvider {
    static var previews: some View {
        MatrixViewControllerPreview().previewDevice("iPhone 12")
    }
}

}

Creating a dynamic 5X5 Matrix
 
 
Q