Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to parse Array of JSON to array in Swift

I'm trying to parse JSON which is like below

[
  {
    "People": [
      "Jack",
      "Jones",
      "Rock",
      "Taylor",
      "Rob"
    ]
  },
  {
    "People": [
      "Rose",
      "John"

    ]
  },
  {
    "People": [
      "Ted"
    ]
  }
]

to an array which results in:

[ ["Jack", "Jones", "Rock", "Taylor", "Rob"] , ["Rose", "John"], ["Ted"] ]

which is array of arrays.

I tried with code below

if let path = Bundle.main.path(forResource: "People", ofType: "json") {
    let peoplesArray = try! JSONSerialization.jsonObject(
            with: Data(contentsOf: URL(fileURLWithPath: path)),
            options: JSONSerialization.ReadingOptions()
    ) as? [AnyObject]
    for people in peoplesArray! {
        print(people)
    }
}

when I print "people" I get o/p as

{
  People = (
    "Jack",
    "Jones",
    "Rock",
    "Taylor",
    "Rob"
  );
}
{
  People = (
    "Rose",
    "John"
  );
}
...

I'm confused how to parse when it has "People" repeated 3 times

Trying to display content in UITableView where my 1st cell has "Jack" .."Rob" and Second cell has "Rose" , "John" and third cell as "Ted"

PLease help me to understand how to achieve this

like image 903
Ashh Avatar asked Feb 07 '17 03:02

Ashh


1 Answers

You can do this in an elegant and type safe way leveraging Swift 4 Decodable

First define a type for your people array.

struct People {
  let names: [String]
}

Then make it Decodable, so that it can be initialised with a JSON.

extension People: Decodable {

  private enum Key: String, CodingKey {
    case names = "People"
  }

  init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: Key.self)

    self.names = try container.decode([String].self, forKey: .names)
  }
}

Now you can easily decode your JSON input

guard
  let url = Bundle.main.url(forResource: "People", withExtension: "json"),
  let data = try? Data(contentsOf: url)
else { /* Insert error handling here */ }

do {
  let people = try JSONDecoder().decode([People].self, from: data)
} catch {
  // I find it handy to keep track of why the decoding has failed. E.g.:
  print(error)
  // Insert error handling here
}

Finally to get get your linear array of names you can do

let names = people.flatMap { $0.names }
// => ["Jack", "Jones", "Rock", "Taylor", "Rob", "Rose", "John", "Ted"]
like image 119
mokagio Avatar answered Sep 19 '22 06:09

mokagio