Home > Back-end >  Swift - How to Change Multi-Level JSON Struct Single Element Value on Condition
Swift - How to Change Multi-Level JSON Struct Single Element Value on Condition

Time:04-29

I have multi-level Struct that converts complex JSON data to a Struct. What I am struggling is to change the dataStruct.group.point.presentValue element value on condition.

var dataStruct : DataStruct = load("jsonfile.json")

 struct DataStruct : Codable {
    let name: String
    var group: [groupData]
}

struct groupData: Codable, Hashable {
    let id, name : String
    var point : [pointInfo]

}

struct pointInfo : Codable, Hashable {
    let id : String
    let address : address
    let name : String
    var presentValue : String
}

struct address: Codable, Hashable {
    let index: String
    let type: String
}

I have tried the following map function, but the compiler complains that the Group in ForEach is 'let' constant. Basically the function is supposed to compare address.index field in the Struct to the passed pointNo variable, and once it has been found (unique), point.presentValue is changed to the new value.

What is the correct way to achieve this?

   func updatePresentValue(pointNo : String) {
        
        dataStruct.group.forEach { Group in
            Group.point = Group.point.map { point -> pointInfo in

                var p = point
                if point.address.index == pointNo {
                    p.presentValue = "New value"
                    return p
                }
                else { return p }
            }
        }
    }

CodePudding user response:

Basically there are two ways.

  • Extract the objects by assigning them to variables, modify them and reassign them to their position in dataStruct.

  • Enumerate the arrays and modify the objects in place.

This is an example of the second way

func updatePresentValue(pointNo : String) {
    for (groupIndex, group) in dataStruct.group.enumerated() {
        for (pointIndex, point) in group.point.enumerated() {
            if point.address.index == pointNo {
                dataStruct.group[groupIndex].point[pointIndex].presentValue = "New value"
            }
        }
    }
 }

CodePudding user response:

It gets more complicated when dealing with multilevel structures but here is one way to do it where we first enumerate over group so we get both the object and the index of the object for each iteration so we can use this index when updating the group array. The inner struct is updated using a mutable copy of point

for (index, group) in dataStruct.group.enumerated() {
    if group.point.contains(where: { $0.address.index == pointNo }) {
        var copy = group
        copy.point = group.point.reduce(into: []) {
            if $1.address.index == pointNo {
                var pointCopy = $1
                pointCopy.presentValue = "new value"
                $0.append(pointCopy)
            } else {
                $0.append($1)
            }
        }
        dataStruct.group[index] = copy
    }
}
  • Related