7

I am trying to parse the following JSON:

{ 
  "String For Key 1": [
    "Some String A",
    "Some String B",
    "Some String C",
  ],
  "String For Key 2": [
    "Some String D",
    "Some String E",
    "Some String F"
  ],
  "String For Key 3": [
    "Some String G",
    "Some String H",
    "Some String I",
  ],
  "String For Key 4": [
    "Some String J",
    "Some String K",
    "Some String L"
  ],
  "String For Key 5": [
    "Some String M",
    "Some String N",
    "Some String O"
  ],
  "String For Key 6": [
    "Some String P",
    "Some String Q",
    "Some String R"
  ]
}

I am also following this tutorial. It's on Github in Playground

In the example, they are parsing an Array of dictionaries using typealias JSONDictionary = [String: AnyObject]

I need to parse a Dictionary that has a Key which is String, and Value that is an Array. Hence: typealias JSONDictionary = [String: [AnyObject]] and I am getting an error when returning a flatMap.

extension Resource {
    init(url: NSURL, parseJSON: AnyObject -> A?) {
        self.url = url
        self.parse = { data in
            let json = try? NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String: [AnyObject]]
           //This is where I get an error
            return json.flatMap(parseJSON)
        }
    }
}

Error:

Cannot convert value of type `AnyObject -> A? to expected argument type `([String: [AnyObject]]?) -> _?

How can I get a dictionary with Keys as String and Values as an Array? I would like to keep their Generic approach.

user1107173
  • 10,334
  • 16
  • 72
  • 117

1 Answers1

8

Type of jsonString is Dictionary<String, Array<String>> You can give it a type like Dictionary<String, AnyObject>

AnyObject can contain class and struct i.e Array, Dictionary, String, Int, Obj C Classes Hence an Array<String> is represented by AnyObject not [AnyObject]

let jsonString:[String: AnyObject] =
[
    "String For Key 1": [
    "http://www.urlToSomePathA.jpg",
    "http://www.urlToSomePathB.jpg",
    "http://www.urlToSomePathC.jpg",
    ],
    "String For Key 2": [
    "http://www.urlToSomePathD.jpg",
    "http://www.urlToSomePathE.jpg",
    "http://www.urlToSomePathF.jpg"
    ]
]

// Now you can map a function on the value type
let values = jsonString.flatMap { $0.1 as? [String] }
print(values)
// RESULT: [["http://www.urlToSomePathA.jpg", "http://www.urlToSomePathB.jpg", "http://www.urlToSomePathC.jpg"], ["http://www.urlToSomePathD.jpg", "http://www.urlToSomePathE.jpg", "http://www.urlToSomePathF.jpg"]]

Update

let keys = jsonString.flatMap { $0.0 } // ["String For Key 1", "String For Key 2"]

As commented by @dffri, you can use keys property on dictionary which will return LazyMapCollection which will realise only if you access the object inside.

let keys = jsonString.keys
Khundragpan
  • 1,952
  • 1
  • 14
  • 22
  • Thanks. This doesn't print the `keys`? How do I get the keys as a `key` and `value` as `Array`? – user1107173 Aug 07 '16 at 14:34
  • @user1107173 I have updated the answer, you can get to keys by `let keys = jsonString.flatMap { $0.0 }` – Khundragpan Aug 07 '16 at 14:37
  • 1
    Note: no need to use `flatMap` for the keys, as there is no attempted casting there (just `let keys = jsonString.map{ $0.0 }` suffices). Alternatively, use the `keys` property of a dictionary to get the keys as a lazy collection: `let keys = jsonString.keys`. – dfrib Aug 07 '16 at 14:40
  • Wait. Please note in my question, I have a dictionary that I am trying to parse, not an array. In your answer, jsonString is an Array. – user1107173 Aug 07 '16 at 14:48
  • @user1107173, jsonString is Dictionary – Khundragpan Aug 07 '16 at 14:50
  • @user1107173. you can get to the Type via, `print((Mirror(reflecting: jsonString)).subjectType)` – Khundragpan Aug 07 '16 at 14:51
  • Sorry, I am confused. First, thank you for your patience and help! Second, your jsonString starts out with an array `[`, while my json starts with a dictionary `{`. Am I missing something? – user1107173 Aug 07 '16 at 14:55
  • If it helps, here is a link to a sample project I created. https://www.dropbox.com/sh/vhbwvei4h6vxyif/AABxi0FSwM9aaOuYN00Dbau2a?dl=0 – user1107173 Aug 07 '16 at 14:55
  • @user1107173, you have posted json as String, when you serialise it with `NSJSONSerialization` and cast as `[String: AnyObject]`, you will get what I have answered as. `Dictionary` is denoted by `[:]`, where as `Array` by `[]`. Notice the **colon** in between parenthesis. – Khundragpan Aug 07 '16 at 14:59
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/120353/discussion-between-user1107173-and-k-nimo). – user1107173 Aug 07 '16 at 15:02