1

I have a struct like:

struct Demo: Codable {
    var foo: String
    var bar: String
    ...
}

And I have an array of demo:

let array = [Demo(foo: "a", bar: "b"), Demo(foo: "c", bar: "d")]

And I want to convert this array to a Dictionary [[String: Any]] with something like this:

let dictionary:[[String : Any]] = array.toDictionaryFromArrayOfCodable()

How can I get it?

Edit: My expected output is something like, and I want to use JSONEncoder:

[["foo": "a", "bar": "b"], ["foo": "c", "bar": "d"]]
Diego Carrera
  • 2,245
  • 1
  • 13
  • 16
  • 2
    https://stackoverflow.com/questions/47922485/encode-struct-and-convert-to-dictionary-string-any ? – Larme Aug 03 '18 at 08:52
  • try this -> let dict = try JSONDecoder().decode([String: Any].self, from: JSONEncoder().encode(array)) – vivekDas Aug 03 '18 at 09:02
  • Edited with de expected output. – Diego Carrera Aug 03 '18 at 09:11
  • @vivekDas using decode([String: Any] I have an error: "Type 'Any does not conform to protocol 'Decodable'. Changing it to decode([String: String], it compiles but I have an error: typeMismatch(Swift.Dictionary, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary but found an array instead.", underlyingError: nil)) – Diego Carrera Aug 03 '18 at 09:24
  • Follow the link @Larme has provided. – nayem Aug 03 '18 at 09:28
  • Possible duplicate of [How can I use Swift’s Codable to encode into a dictionary?](https://stackoverflow.com/questions/45209743/how-can-i-use-swift-s-codable-to-encode-into-a-dictionary) – nayem Aug 03 '18 at 09:32
  • @nayem in this question he asked to encode an object to a dictionary. I want to encode an array of objects to an array of dictionaries. I will follow this question to have a solution. Thanks. – Diego Carrera Aug 03 '18 at 09:37
  • Yes! That should do it. You will just need to use `map` with your array of objects. – nayem Aug 03 '18 at 09:40
  • `let array = [Demo(foo: "a", bar: "b"), Demo(foo: "c", bar: "d")]; print("array: \(array)"); let encodedData = try! JSONEncoder().encode(array); let encodedStr = String(data: encodedData, encoding: .utf8); print("encodedStr: \(encodedStr!)")` make it works. => `$>encodedStr: [{"foo":"a","bar":"b"},{"foo":"c","bar":"d"}]`. But the output you gave is not valid JSON. You should have curved bracelets (`{}`) for dictionaries, not squared ones (`[]`) (I forced unwrapped for the sake of the logic, don't force unwrap) – Larme Aug 03 '18 at 10:55

1 Answers1

2

I found a solution using two extensions: - First to get a dictionary from an object - Second, to create an array of dictionaries with each elements of an array, using first extension:

Usage:

let dictionary = [Demo].asDictionaryFromArray()
print(dictionary)

output as expected: [["bar": b, "foo": a], ["bar": d, "foo": c]]

extension Encodable {

    var dictionaryFromObject: [String: Any]? {
        guard let data = try? JSONEncoder().encode(self) else { return nil }
        return (try? JSONSerialization.jsonObject(with: data, options: .allowFragments)).flatMap { $0 as? [String: Any] }
    }

}

extension Array where Element: Encodable {

    func asDictionaryFromArray() -> [[String: Any]] {
        var dict = [[String: Any]]()

        _ = self.map {
            if let objectDict = $0.dictionaryFromObject {
                dict.append(objectDict)
            }
        }

        return dict
    }

}
Diego Carrera
  • 2,245
  • 1
  • 13
  • 16