0

I trying to count the number of non empty string in a struct to set the numberOfRow in the tableView. Some of data will return me "" when the data no need to be display in the tableView. So I need to count the numberOfRow according to the non "" in the struct. But I have no idea how to do so.

I need to get the number of row according to non "" in the Post struct below.

struct Post : Codable {
    let postID : Int?
    let postName : String?
    let postDetail : String?
    let postDesc : String?
}

I want to get 3 from the JSON data below since the postDesc is "". How can I count to get the 3.

{
     "postID": 325,
     "postName": "Test1",
     "postDetail": "Test1",
     "postDesc": "",
}
Aatrox11
  • 65
  • 4

2 Answers2

1

This sounds like a strange thing to want to do.

protocol EmptyTest {
    var isEmpty: Bool { get }
}

extension Optional: EmptyTest where Wrapped: EmptyTest {
    var isEmpty: Bool {
        switch self {
        case .none:
            return true
        case let .some(s):
            return s.isEmpty
        }
    }
}

extension String: EmptyTest {}

extension Post {
    var nonEmptyProperties: [Any] {
        Mirror(reflecting: self)
            .children
            .filter { $0.value is EmptyTest }
            .reduce([]) { e, p in
                (p.value as! EmptyTest).isEmpty == true ? e :
                e + [p]
        }
    }
}

Post(postID: nil, postName: "name", postDetail: nil, postDesc: "Desc")
    .nonEmptyProperties
    .count
Shadowrun
  • 3,572
  • 1
  • 15
  • 13
0

Test run this on Playground

Option 1: Check using Dictionary

func convertToDictionary(json: String) -> [String: Any]? {
    if let data = json.data(using: .utf8) {
        do {
            return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
        } catch {
            print(error.localizedDescription)
        }
    }
    return nil
}

func getNonEmptyCount(dict: [String: Any]?) -> Int {
    return dict?.filter({
        if let value = $0.value as? String {
            return !value.isEmpty
        } else if let value = $0.value as? Int {
            return value > 0
        } else {
            return false
        }
    }).count ?? 0
}

let json = """
{
     "postID": 325,
     "postName": "Test1",
     "postDetail": "Test1",
     "postDesc": "",
}
"""
getNonEmptyCount(dict: convertToDictionary(json: json))

Option 2: Check using Mirror

let json = """
{
     "postID": 325,
     "postName": "Test1",
     "postDetail": "Test1",
     "postDesc": "",
}
"""

func getNonEmptyCount(json: String) -> Int {
    let model = try! JSONDecoder().decode(Post.self, from: json.data(using: .utf8)!)
    let mirror = Mirror(reflecting: model)
    return mirror.children.filter {
        if let value = $0.value as? String {
            return !value.isEmpty
        } else if let value = $0.value as? Int {
            return value > 0
        } else {
            return false
        }
    }.count
}

print(getNonEmptyCount(json: json))
ChanOnly123
  • 1,004
  • 10
  • 12
  • Since user is using Codable and has already parsed the JSON, going back to JSONData (JSONEncoder), then back to Dictionary (JSONSerialization), to make a count might be overkill over enumerating the values of the struct and check them. – Larme Mar 17 '21 at 08:34
  • Also because of the strange requirements OP has for how to count nil values I am not sure this can be made to work properly (see the comments to the question) – Joakim Danielson Mar 17 '21 at 08:37