【问题标题】:Swift 4 Struct Searching by parameter with containsSwift 4 Struct 通过参数搜索包含
【发布时间】:2018-06-22 07:54:40
【问题描述】:

我有结构数组,但我真的不知道如何通过结构的参数之一使用搜索。

我的结构看起来像:

struct Actor {
   var name: String!
   var posterURL: String!

    init(_ dictionary: [String: Any]) {
       name = dictionary["name"] as! String
       posterURL = dictionary["image"] as! String
    }
}

所以,我尝试使用谓词

let actorSearchPredicate = NSPredicate(format: "name contains[c] %@", text)
filterredActors = (actors as NSArray).filtered(using: actorSearchPredicate)

但是,当我尝试输入任何内容时,它会因错误而崩溃

[<_SwiftValue 0x10657ffb0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key name.'

在结构中使用谓词搜索的正确方法是什么? 谢谢

【问题讨论】:

  • 为什么要打扰NSPredicate? actors.filtered{ $0.name.contains(text) }
  • $0.name.contains(text) 唯一缺少的就是不区分大小写。
  • 不区分大小写的一种非常简单的方法是$0.name.lowercased().contains(text.lowercased())。
  • 你为什么选择AnyObject?你根本不应该在 Swift 4 中使用它。试试actors.filtered{( $0.name.lowercased().contains(text.lowercased()) )}。此外,filter 和 filtered 之间也存在差异。确保您使用的是filtered。

标签: arrays swift search struct predicate


【解决方案1】:

NSPredicate 不需要,Swift 有方便的方法来检查不区分大小写

whether the receiver contains a given string by performing a case insensitive, locale-aware search.

filterredActors = actors.filter { $0.name.localizedCaseInsensitiveContains(text) }

和不区分大小写和变音符号

whether the receiver contains a given string by performing a case and diacritic insensitive, locale-aware search.

filterredActors = actors.filter { $0.name.localizedStandardContains(text) }

【讨论】:

    【解决方案2】:

    如果您需要使用谓词来过滤结构,您无需进入@objc 领域或将您的数据转换为NSArray 即可:

    func filter(actors: [Actor], named: String) -> [Actor] {
        let predicate = NSPredicate(format: "SELF contains[cd] %@", named)
        return actors.filter {
            predicate.evaluate(with: $0.name)
        }
    }
    

    例子:

    struct Actor {
        let name: String
        let imdb: String
    }
    
    let actors = [
        Actor(name: "John Travolta", imdb: "http://www.imdb.com/name/nm0000237"),
        Actor(name: "Uma Thurman", imdb: "http://www.imdb.com/name/nm0000235"),
        Actor(name: "Samuel L. Jackson", imdb: "http://www.imdb.com/name/nm0000 168"),
        Actor(name: "Penélope Cruz", imdb: "http://www.imdb.com/name/nm0004851"),
        Actor(name: "Penelope Ann Miller", imdb: "http://www.imdb.com/name/nm0000542")
    ]
    
    print(filter(actors: actors, named: "Uma").map { $0.name })
    // ["Uma Thurman"]
    print(filter(actors: actors, named: "J").map { $0.name })
    // ["John Travolta", "Samuel L. Jackson"]
    

    使用谓词进行过滤很有用,例如,可以考虑变音符号。让我们搜索带有重音字符的演员姓名:

    print(filter(actors: actors, named: "Penelope").map { $0.name })
    // ["Penélope Cruz", "Penelope Ann Miller"]
    

    它同时找到“Penelope”,带和不带重音“e”。

    在这种情况下使用 String.contains 将不起作用:

    let text = "Penelope"
    let hits = actors.filter { ( $0.name.lowercased().contains(text.lowercased()) )}
    print(hits.map { $0.name })
    // ["Penelope Ann Miller"]
    

    还有更好的选择(String 本地化搜索、正则表达式、String.range(of:options:range:locale),...)。使用谓词并不快(也不慢很多)。如果您已经知道,使用谓词语法可能更容易推理复杂的查询。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-18
      • 1970-01-01
      • 1970-01-01
      • 2023-03-15
      • 1970-01-01
      • 1970-01-01
      • 2023-01-19
      • 2015-01-05
      相关资源
      最近更新 更多