1

作成中のアプリ内に検索を実装しようとしています。検索しようとしている配列があり、このコードをオンラインで見つけました。

 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 を使用しています

4

3 に答える 3

1

@appzYourLife のソリューションの改善として、ネイティブ Swift でこれを行うことができますSet。この場合、カウントされたセットは必ずしも必要ではないためです。これmap(_:)により、各名前の文字を重ねて Objective-C に橋渡しする必要がなくなります。のように、一連の を使用できるようになりCharacterました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(_:_:)andを使用できます。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()
}
于 2016-08-14T10:02:28.690 に答える
0

まず、このようなコードのブロック

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()
}
于 2016-08-13T23:21:54.687 に答える