【问题标题】:Filter a nested array and dictionary过滤嵌套数组和字典
【发布时间】:2019-02-12 05:07:03
【问题描述】:

我正在尝试过滤其中包含数组和字典的数组。我想根据服务的类型进行过滤,然后在属性数组下其 isPrimaryMailbox 为 Yes。 这就是我所做的:-

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

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

但这显示了 isPrimaryMailbox 值为 No 的数据

以下是 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"
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
}

【问题讨论】:

  • 什么是services 对象。您要过滤的字典。
  • 你总是考虑第一个属性,你必须重新过滤 $0.attributes 以返回 isPrimaryMailbox 然后检查它的值。
  • 我无法理解你的问题。
  • 是否有公共 api 来获取这个 json ?
  • @s3cretshadow 现在我正在使用本地 json 文件。

标签: ios arrays swift filter realm


【解决方案1】:

你可以试试这个:

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 格式错误。如果你要使用一个关联的 Array,那你为什么要把 key 和 value 分开到不同的 key-value 对呢?

attributes 可以是:

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

使用布尔值代替字符串“YES”或“NO”

这样当你过滤时,你就简单地说

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

或者如果你真的更喜欢字符串“YES”,那么:

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

【讨论】:

  • 根据服务器响应,我无法更改。
【解决方案2】:

我不知道服务对象的类型。但您可以通过以下方式从 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

已编辑:

如果不想使用 for 循环,可以只使用 filter 和 reduce:


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 编译器现在还不够聪明,无法在第一次匹配后停止 reduce 循环(false || true 总是给出 true。如果我们有一个 true,则无需继续。

【讨论】:

  • 我想使用过滤器之类的高阶函数,for循环不是个好主意。
猜你喜欢
  • 2020-05-23
  • 1970-01-01
  • 2017-06-07
  • 2018-04-18
  • 1970-01-01
  • 2021-09-19
  • 2021-11-21
  • 1970-01-01
相关资源
最近更新 更多