Фильтровать вложенный массив и словарь - PullRequest
0 голосов
/ 12 февраля 2019

Я пытаюсь отфильтровать массив, который состоит из массива и словаря внутри него.Я хочу фильтровать на основе типа службы, а затем, чей isPrimaryMailbox Да в массиве атрибутов.Это то, что я сделал: -

let services = Manager.realm().objects(Service.self).filter("type = %@", "MAILBOX")

let serviceWithPrimaryEmail = services.filter({$0.attributes.first?.value == "Yes"})

Но это показывает, что данные, значение isPrimaryMailbox которых равно Нет

Ниже приведен ответ json: -

{
  "data": {
    "cust": [
      {
        "customerId": "2040349110",
        "serv": [
          {
            "bill": "2010007656959",
            "services": [
              {
"type": "MOBILE",
                "status": "ACTIVE",
                "plan": {
                  "name": "Mobil"
                },
                "addOns": [
                  {
                    "status": "Active"
                  }
                ],
                "hardware": [
                  {
                    "type": "HANDSET"
                  }
                ]
              },
              {
                "type": "MOBILE",
                "plan": {
                  "name": "Mobile Service"
                },
                "addOns": [
                  {
                    "status": "Active"
                  }
                ],
                "hardware": [
                  {
                    "type": "HANDSET",
                  }
                ]
              },
              {
                "type": "MAILBOX",
                "plan": {
                  "name": "Service"
                },
                "attributes": [
                  {
                    "name": "mailboxSize",
                    "value": "1 GB"
                  },
                  {
                    "name": "isPrimaryMailbox",
                    "value": "Yes"
                  }
                ]
              },
              {
                "type": "MAILBOX",
                "status": "ACTIVE",
                "plan": {
                  "name": "Service"
                },
                "attributes": [
                  {
                    "name": "mailboxSize",
                    "value": "1 GB"
                  },
                  {
                    "name": "isPrimaryMailbox",
                    "value": "No"
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
}

Ответы [ 2 ]

0 голосов
/ 12 февраля 2019

Я не знаю тип объекта услуг.Но вот как вы можете получить первичный почтовый сервис из вашего JSON:


typealias JSON = [String: Any]
let json = yourJSONDict as? JSON
let services = (((json["data"] as? JSON)?["cust"] as? JSON)?["serv"] as? JSON)?["services"] as? [JSON]
let primaryEmailService = services?.filter { service in
    if (service["type"] as? String) == "MAILBOX" {
        for attribute in service["attributes"] as? [[String: String]] ?? [] {
            if (attribute["name"] == "isPrimaryMailbox") && (attribute["value"] == "Yes") {
                return true
            }
        }
    }

    return false
}
    .first

Отредактировано:

Если вы не хотите использовать для цикла, вы можетеиспользуйте фильтр и уменьшайте только:


let primaryEmailService = services?
    .filter {
        let attributes = $0["attributes"] as? [[String: String]] ?? []

        return ($0["type"] as? String) == "MAILBOX"
            && attributes.reduce(false, { $0 || (($1["name"] == "isPrimaryMailbox") && ($1["value"] == "Yes")) })
}
    .first

Обратите внимание, что сложность в худшем случае для обоих подходов одинакова.Но в первом случае сложность для первого подхода лучше, потому что вам не нужно перебирать все атрибуты в функции Reduce.И компилятор Swift на данный момент недостаточно умен, чтобы прекратить сокращать цикл после первого совпадения (false || true всегда дает true. Нет необходимости продолжать, если у нас есть один true).

0 голосов
/ 12 февраля 2019

Вы можете попробовать это:

let serviceWithPrimaryEmail = services.filter({$0.attributes.[1].value == "Yes"})
// I used the index 1 because as I see in you JSON data, the isPrimaryMailBox is always in the second row.

Кроме того, ваш JSON плохо отформатирован.Если вы собираетесь использовать связанный массив, то почему вы должны разделить ключ и значение на другую пару ключ-значение?

attributes может быть просто:

"attributes":  {
  "mailboxSize":"1 GB",
  "isPrimaryMailbox":true
}

Использование логического выражения вместо строки «ДА» или «НЕТ»

Чтобы при фильтрации вы просто сказали:

let serviceWithPrimaryEmail = services.filter({$0.attributes["isPrimaryMailbox"]})

Или, если вы действительно предпочитаете строку «ДА», тогда:

let serviceWithPrimaryEmail = services.filter({$0.attributes["isPrimaryMailbox"] == "YES"})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...