ynizhenie
@ynizhenie

Как сделать филтер структуры?

Здравствуйте.
Получаю вот такой массив данных.
Массив
[
  {
"idSite": 204233,
"status": 0,
"Name": "",
"timeOfStatus": null
},
  {
"idSite": 204234,
"status": 0,
"Name": "",
"timeOfStatus": null
},
  {
"idSite": 204235,
"status": 0,
"Name": "",
"timeOfStatus": null
},
  {
"idSite": 204236,
"status": 1,
"Name": "OK",
"timeOfStatus": "2019-06-26 12:58:16"
}
]

Сохраняю его в структру:
self.Obj = try JSONDecoder().decode([StatusObjects].self, from: data)

Структура выглядит так:
Структура
struct  StatusObjects: Decodable {
    let idSite: Int?
    let status: Int?
    let Name: String?
    let timeOfStatus: String?
    
    func convertToDictionary() -> Any {
        return ["idSite": idSite!, "status": status!, "Name": Name!,"timeOfStatus": timeOfStatus!]
        
    }
}

Как мне отфильтровать структуру или массив . Что бы оставались только объекты со:
"status": 1
  • Вопрос задан
  • 74 просмотра
Решения вопроса 1
doublench21
@doublench21 Куратор тега Swift
Покажу вам два варианта.

--------------------------------------------------------
Вариант простой(aka Думми):
Обычная фильтрация, после того как память уже выделена. Просто, но разброс по памяти и скорость ниже.
Код с подсветкой
5d1398ab0b187603385123.png


--------------------------------------------------------
Вариант продвинутый:
Исправляем наименование свойств.
Преобразуем даты в соответствующий формат.
Проводим свою кастомную кодировку, отслеживая статус и выкидывая ошибку, дабы не выделять зря память.
Код с подсветкой
2QkNeGLn.png
Код текстом
import Foundation

    let json = """
    [{
        "idSite": 204233,
        "status": 0,
        "Name": "",
        "timeOfStatus": null
    },
    {
        "idSite": 204234,
        "status": 0,
        "Name": "",
        "timeOfStatus": null
    },
    {
        "idSite": 204235,
        "status": 0,
        "Name": "",
        "timeOfStatus": null
    },
    {
        "idSite": 204236,
        "status": 1,
        "Name": "OK",
        "timeOfStatus": "2019-06-26 12:58:16"
    }]
    """

    struct SomeStruct: Decodable {
      let idSite: Int
      let status: Bool
      let name: String
      let timeOfStatus: Date?

      // Преобразуем Name -> name
      private enum CodingKeys: String, CodingKey {
        case idSite
        case status
        case name = "Name"
        case timeOfStatus
      }

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

        self.idSite = try container.decode(Int.self, forKey: .idSite)

        // Выбрасываем ошибку, если статус не равен 1. Не выделяем зря память.
        let status = try container.decode(Int.self, forKey: .status)
        if status == 1 {
          self.status = true
        } else {
          throw DecodingError.dataCorruptedError(forKey: .status, in: container, debugDescription: "Status mast be `1`")
        }

        self.name = try container.decode(String.self, forKey: .name)

        // Преобразуем строку с датой в объект для работы с датами Date
        let date = try? container.decode(String.self, forKey: .timeOfStatus)
        let dateFormatter: DateFormatter = {
          $0.dateFormat = "yyyy-MM-dd HH:mm:ss"
          $0.calendar = Calendar(identifier: .iso8601)
          $0.timeZone = TimeZone(secondsFromGMT: 0)
          $0.locale = Locale(identifier: "en_US_POSIX")
          return $0
        }(DateFormatter())
        self.timeOfStatus = date != nil ? dateFormatter.date(from: date!) : nil
      }
    }

    // Тип обёртка, которая даст легко отфильтровать данные, от тех, которые не прошли из-за статуса.
    enum Throwable<T: Decodable>: Decodable {
      case success(T), failure(Error)

      init(from decoder: Decoder) throws {
        do {
          let decoded = try T(from: decoder)
          self = .success(decoded)
        } catch let error {
          self = .failure(error)
        }
      }

      var value: T? {
        switch self {
        case .failure(_):
          return nil
        case .success(let value):
          return value
        }
      }
    }


    let decoder = JSONDecoder()
    let arrayOfSomeStructs = try! decoder.decode([Throwable<SomeStruct>].self, from: json.data(using: .utf8)!)
    let filteredArrayOfSomeStructs = arrayOfSomeStructs.compactMap{ $0.value }
    print(filteredArrayOfSomeStructs.count)
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы