Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert Array of Dictionary to custom object swift

Tags:

ios

swift

I have:

    let countries : [[String : Any]] = [
            [
                "name" : "Afghanistan",
                "dial_code": "+93",
                "code": "AF"
            ],
            [
                "name": "Aland Islands",
                "dial_code": "+358",
                "code": "AX"
            ],
            [
                "name": "Albania",
                "dial_code": "+355",
                "code": "AL"
            ],
            [
                "name": "Algeria",
                "dial_code": "+213",
                "code": "DZ"
            ]
]

I want to add all this array of dictionary to my custom object like

let country:[Country] = countries

My custom object looks like this:

class Country: NSObject {
        let name: String
        let dial_code : String
        let code: String

        init(name: String, dial_code: String, code: String) {
            self.name = name
            self.dial_code = dial_code
            self.code = code
        }
    }

I understand that I need a loop thru the array but idk what is the next step. Would be great to have an example.

like image 659
Artyom Avatar asked Dec 07 '17 14:12

Artyom


4 Answers

You should make your Country conform to Codable protocol, convert your dictionary to JSON data using JSONSerialization and then just decode the Data using JSONDecoder, note that you can set its keyDecodingStrategy property to convertFromSnakeCase auto avoid the need to declare custom coding keys like dial_Code:

struct Country: Codable {
    let name: String
    let dialCode : String
    let code: String
}

do {
    let json = try JSONSerialization.data(withJSONObject: countries)
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    let decodedCountries = try decoder.decode([Country].self, from: json)
    decodedCountries.forEach{print($0)}
} catch {
    print(error)
}

Country(name: "Afghanistan", dialCode: "+93", code: "AF")

Country(name: "Aland Islands", dialCode: "+358", code: "AX")

Country(name: "Albania", dialCode: "+355", code: "AL")

Country(name: "Algeria", dialCode: "+213", code: "DZ")

like image 153
Leo Dabus Avatar answered Oct 22 '22 12:10

Leo Dabus


You can use flatMap method of a list to produce the result:

countries.flatMap { (v: [String: Any]) -> Country? in
    if let name = v["name"] as? String, 
       let dial = v["dial_code"] as? String, 
       let code = v["code"] as? String {
        return Country(name: name, dial_code: dial, code: code)
    } else {
        return nil
    }
}

A full example would be:

//: Playground - noun: a place where people can play

import UIKit

let countries : [[String : Any]] = [
    [
        "name" : "Afghanistan",
        "dial_code": "+93",
        "code": "AF"
    ],
    [
        "name": "Aland Islands",
        "dial_code": "+358",
        "code": "AX"
    ],
    [
        "name": "Albania",
        "dial_code": "+355",
        "code": "AL"
    ],
    [
        "name": "Algeria",
        "dial_code": "+213",
        "code": "DZ"
    ]
]

class Country: NSObject {
    let name: String
    let dial_code : String
    let code: String

    init(name: String, dial_code: String, code: String) {
        self.name = name
        self.dial_code = dial_code
        self.code = code
    }
}

let cnt = countries.flatMap { (v: [String: Any]) -> Country? in
    if let name = v["name"] as? String, let dial = v["dial_code"] as? String, let code = v["code"] as? String {
        return Country(name: name, dial_code: dial, code: code)
    } else {
        return nil
    }
}

print (cnt)
like image 29
kender Avatar answered Oct 22 '22 11:10

kender


Not related but remove NSObject until you are required

That is very simple thing you just need to think a bit

Create Object like this

var arr = [Country]()

Now Loop your array of dictionary

  for dict in countries {
      // Condition required to check for type safety :)
        guard let name = dict["name"] as? String, 
              let dialCode = dict["dial_code"] as? String, 
              let code = dict["code"] as? String else {
              print("Something is not well")
             continue
         }
        let object = Country(name: name, dial_code:dialCode, code:code)
         arr.append(object)
    }
  

That's it You have converted array of dict to Custom Object

Hope it is helpful to you

like image 27
Prashant Tukadiya Avatar answered Oct 22 '22 10:10

Prashant Tukadiya


There are a lot of answers already, but I find that there are short comings with most of them. This is what I would suggest:

extension Country {
    init?(fromDict dict: [String: Any]) {
        guard let name = dict["name"] as? String, 
              let dialCode = dict["dial_code"] as? String, 
              let code = dict["code"] as? String else {
            return nil
        }
        self.init(name: name, dialCode: dialCode, code: code)
    }
}

let countries = countryDictionaries.map { dict -> Country in
    if let country = Country(fromDict: dict) { return Country }
    else {
        preconditionFailure("Tried to convert an invalid dict into a country")
        // TODO: handle error appropriately
    }
}

If you just want to ignore invalid country dictionaries, that's even easier:

let countries = countryDictionaries.flatMap(Country.init(fromDict:))
like image 30
Alexander Avatar answered Oct 22 '22 12:10

Alexander