【问题标题】:How to find if a string contains all the characters of a string for live searching in Swift?如何查找字符串是否包含字符串的所有字符以在 Swift 中进行实时搜索?
【发布时间】:2016-08-13 22:37:17
【问题描述】:

我正在尝试在我正在制作的应用中实现搜索。我有一个要搜索的数组,我在网上找到了这段代码:

 func filterContentForSearchText(searchText: String) {
        filteredCandies = candies.filter({( candy : Candies) -> Bool in
        if         candy.name.lowercaseString.containsString(searchText.lowercaseString) == true  {
            return true
        } else {
            return false
        }
    })
    tableView.reloadData()
}

问题是我试图在其上实现搜索的数据库中的文本都被打乱了,因为它应该被缩短。我怎样才能做到这一点,以便搜索检查是否所有字母都在那里,而不是搜索正确的名称。来自数据库 (USDA) 的对象示例:CRAB、DUNGINESS、RAW 如果您有答案,请使其足够快以进行实时搜索。非实时搜索让搜索变得很糟糕(至少对我而言)!

我正在使用 Swift 2.2 和 Xcode 7

【问题讨论】:

  • 为什么会被打乱,什么样的用户搜索会以任意顺序查找匹配的字符?
  • 数据库由美国农业部编写。

标签: swift livesearch


【解决方案1】:

作为对@appzYourLife's solution 的改进,您可以使用本机Swift Set 来执行此操作,因为在这种情况下不一定需要计数集。这将省去map(_:) 覆盖每个名称的字符并将它们桥接到Objective-C。您现在可以只使用一组Characters,因为它们是Hashable

例如:

struct Candy {
    let name: String
}

let candies = [Candy(name: "CRAB"), Candy(name: "DUNGINESS"), Candy(name: "RAW")]    
var filteredCandies = [Candy]()

func filterContentForSearchText(searchText: String) {
    let searchCharacters = Set(searchText.lowercaseString.characters)
    filteredCandies = candies.filter {Set($0.name.lowercaseString.characters).isSupersetOf(searchCharacters)}
    tableView.reloadData()
}

filterContentForSearchText("RA")
print(filteredCandies) // [Candy(name: "CRAB"), Candy(name: "RAW")]

filterContentForSearchText("ED")
print(filteredCandies) // Candy(name: "DUNGINESS")]

还取决于您是否可以将此识别为性能瓶颈(您应该先进行一些分析)——您可以通过缓存包含“糖果”名称字符的集合来进一步优化上述内容,从而避免重新创建每次搜索时都会更新它们(尽管如果您更新 candies 数据,您必须确保它们已更新)。

当你来搜索的时候,你可以使用zip(_:_:)flatMap(_:)来过滤掉对应的糖果。

let candies = [Candy(name: "CRAB"), Candy(name: "DUNGINESS"), Candy(name: "RAW")]

// cached sets of (lowercased) candy name characters
let candyNameCharacterSets = candies.map {Set($0.name.lowercaseString.characters)}

var filteredCandies = [Candy]()

func filterContentForSearchText(searchText: String) {
    let searchCharacters = Set(searchText.lowercaseString.characters)
    filteredCandies = zip(candyNameCharacterSets, candies).flatMap {$0.isSupersetOf(searchCharacters) ? $1 : nil}
    tableView.reloadData()
}

【讨论】:

    【解决方案2】:

    首先是这样的代码块

    if someCondition == true {
       return true
    } else {
       return false
    }
    

    也可以这样写

    return someCondition
    

    对吗? :)

    重构

    所以你的原始代码看起来像这样

    func filterContentForSearchText(searchText: String) {
        filteredCandies = candies.filter { $0.name.lowercaseString.containsString(searchText.lowercaseString) }
        tableView.reloadData()
    }
    

    加扰搜索

    现在,给定一个字符串 A,你想知道另一个字符串 B 是否包含 A 的所有字符吗?

    为此,我们需要 Swift 3 中提供的 CountedSet。由于您使用的是 Swift 2.2,我们将使用旧的 NSCountedSet,但需要一些与 Objective-C 的桥接。

    这是代码。

    struct Candy {
        let name: String
    }
    
    
    let candies = [Candy]()
    var filteredCandies = [Candy]()
    
    func filterContentForSearchText(searchText: String) {
    
        let keywordChars = NSCountedSet(array:Array(searchText.lowercaseString.characters).map { String($0) })
    
        filteredCandies = candies.filter {
            let candyChars = NSCountedSet(array:Array($0.name.lowercaseString.characters).map { String($0) }) as Set<NSObject>
            return keywordChars.isSubsetOfSet(candyChars)
        }
    
        tableView.reloadData()
    }
    

    【讨论】:

      【解决方案3】:

      Swift 3 代码更新:

      func filterContentForSearchText(searchText: String, scope: String = "All") {
        filteredCandies = candies.filter { candy in
          return candy.name.localizedLowercase.contains(searchText.lowercased())
        }
      
        tableView.reloadData()
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-01-15
        • 2019-06-07
        • 1970-01-01
        • 2021-08-13
        • 1970-01-01
        • 2011-05-14
        • 1970-01-01
        • 2011-03-22
        相关资源
        最近更新 更多