Benjamin B.
Benjamin B.

Reputation: 793

Swift - searching a JSON file for a particular value and fetching the entire array of dictionaries in the same array

This is a bit convoluted, but I have a JSON file with zip code and city data, formatted like so:

[{
    "zip_code" : 32071,
    "latitude" : 30.036193,
    "longitude" : -82.932228,
    "city" : "O Brien",
    "state" : "FL",
    "county" : "Suwannee"
  },
  {
    "zip_code" : 32072,
    "latitude" : 30.36036,
    "longitude" : -82.25418,
    "city" : "Olustee",
    "state" : "FL",
    "county" : "Baker"
  },
  {
    "zip_code" : 32073,
    "latitude" : 30.119884,
    "longitude" : -81.791546,
    "city" : "Orange Park",
    "state" : "FL",
    "county" : "Clay"
  },
  {
    "zip_code" : 32079,
    "latitude" : 29.984882,
    "longitude" : -81.802221,
    "city" : "Penney Farms",
    "state" : "FL",
    "county" : "Clay"
  },
  {
    "zip_code" : 32080,
    "latitude" : "",
    "longitude" : "",
    "city" : "Saint Augustine",
    "state" : "FL",
    "county" : "Saint Johns"
  },
  {
    "zip_code" : 46929,
    "latitude" : 40.556269,
    "longitude" : -86.490521,
    "city" : "Flora",
    "state" : "IN",
    "county" : "Carroll"
  }]

What I'm trying to do in my app is give it a zip code and return the data from the array containing that zip code. So, if I'm looking for 32071, it would return the zip, latitude, longitude, etc in an object, where I can then reference it via object.city or object.county.

Tried doing this with a getIndex(for:) but it didn't work. I'm able to print the decoded data successfully, I just cannot get the next step to work.

Edit: this is my decoder:

struct City: Codable {
    let zipCode: Int
    let latitude, longitude: Itude
    let city: String
    let state: State
    let county: String

    enum CodingKeys: String, CodingKey {
        case zipCode = "zip_code"
        case latitude, longitude, city, state, county
    }
}

enum Itude: Codable {
    case double(Double)
    case string(String)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(Double.self) {
            self = .double(x)
            return
        }
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        throw DecodingError.typeMismatch(Itude.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for Itude"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .double(let x):
            try container.encode(x)
        case .string(let x):
            try container.encode(x)
        }
    }
}

enum State: String, Codable {
    case aa = "AA"
    case ae = "AE"
    case ak = "AK"
    case al = "AL"
    case ap = "AP"
    case ar = "AR"
    case az = "AZ"
    case ca = "CA"
    case co = "CO"
    case ct = "CT"
    case dc = "DC"
    case de = "DE"
    case fl = "FL"
    case fm = "FM"
    case ga = "GA"
    case gu = "GU"
    case hi = "HI"
    case ia = "IA"
    case id = "ID"
    case il = "IL"
    case ks = "KS"
    case ky = "KY"
    case la = "LA"
    case ma = "MA"
    case md = "MD"
    case me = "ME"
    case mh = "MH"
    case mi = "MI"
    case mn = "MN"
    case mo = "MO"
    case mp = "MP"
    case ms = "MS"
    case mt = "MT"
    case nc = "NC"
    case nd = "ND"
    case ne = "NE"
    case nh = "NH"
    case nj = "NJ"
    case nm = "NM"
    case nv = "NV"
    case ny = "NY"
    case oh = "OH"
    case ok = "OK"
    case or = "OR"
    case pa = "PA"
    case pr = "PR"
    case pw = "PW"
    case ri = "RI"
    case sc = "SC"
    case sd = "SD"
    case stateAS = "AS"
    case stateIN = "IN"
    case tn = "TN"
    case tx = "TX"
    case ut = "UT"
    case va = "VA"
    case vi = "VI"
    case vt = "VT"
    case wa = "WA"
    case wi = "WI"
    case wv = "WV"
    case wy = "WY"
}

typealias Cities = [City]

Upvotes: 1

Views: 410

Answers (1)

pawello2222
pawello2222

Reputation: 54641

You can use first(where:) - note that this produces an Optional

let result = try JSONDecoder().decode(Cities.self, from: jsonStr)

if let object = result.first(where: { $0.zipCode == 32071 }) {
    print(object.county) // prints "Suwannee"
}

If you want to get more than one object you can use filter

let objects = result.filter { $0.zipCode == 32071 }

Upvotes: 1

Related Questions