OlivierM
OlivierM

Reputation: 165

Swift: How to filter UISearchBar for multiple strings?

I want to type in a UISearchBar 2 Strings.

For ex. bob man.

let itemArray: [searchItem] = [
        searchItem(title: "Bob", subtitle: "Man"),
        searchItem(title: "Bob", subtitle: "Woman"),
        searchItem(title: "Joe", subtitle: "Man")
]

var filteredArray = [searchItem]() 

How can I make sure I get the follow searchItem back:

Only searchItem(title: "Bob", subtitle: "Man") because only that matches bob AND man.

When you would search for only bob you would get 2 items back:

searchItem(title: "Bob", subtitle: "Man"),
searchItem(title: "Bob", subtitle: "Woman")

The code I already have:

filteredArray = itemArray.filter { obj in
    obj.title.lowercased().contains(searchBarText.lowercased()) ||
    obj.subtitle.lowercased().contains(searchBarText.lowercased())
}

Upvotes: 1

Views: 91

Answers (1)

vpoltave
vpoltave

Reputation: 1770

I did find a solution, sure it's not the best in case of performance, but you can go from here and improve my answer.

I test it in Playground, i did leave some comments, if you need more information let me know, here is a simple code:


import Foundation

struct SearchItem {
    let title: String
    let subtitle: String
}

/// Trim white spaces from start and end, and map all words to lowercase
let searchedWords = "Bob man woman"
    .trimmingCharacters(in: .whitespacesAndNewlines)
    .components(separatedBy: " ")
    .map { $0.lowercased() }

let itemArray: [SearchItem] = [
    SearchItem(title: "Bob", subtitle: "Woman"),
    SearchItem(title: "Joe", subtitle: "Man"),
    SearchItem(title: "Bob", subtitle: "Man")
]

/// Lowercase all itemArray
let lowercasedItems = itemArray
    .map { SearchItem(title: $0.title.lowercased(), subtitle: $0.subtitle.lowercased()) }

/// First trying to find best result which is contains both `title` and `subtitle`
var filteredArray = lowercasedItems
    .filter { searchedWords.contains($0.title) && searchedWords.contains($0.subtitle) }

/// `filteredArray.isEmpty == false`, then we didn't find best result which contains both `title` and `subtitle`
/// `filteredArray.isEmpty == true` then we'll try to find at least one match
if filteredArray.isEmpty {
    filteredArray = lowercasedItems
        .filter { searchedWords.contains($0.title) || searchedWords.contains($0.subtitle) }
}

print(searchedWords)
print(filteredArray)

Hope this will help you!

Upvotes: 1

Related Questions