0

I have a situation where a value contains multiple fields, and provide a search bar where a user may enter phrases that could be split between those fields.

The following is a short sample from a playground illustrating what I would like to accomplish.

import Foundation

struct Item {
    let name: String
    let size: String
}
let itemA = Item(name: "stuff", size: "Large")
let itemB = Item(name: "something", size: "X-Large")
let items = [itemA, itemB]

let singleSearch = "stuff"
let singleFound = items.filter { $0.name.localizedStandardContains(singleSearch) ||
    $0.size.localizedStandardContains(singleSearch)
}
print(singleFound) // ItemA

let multiSearch = "stuff large"
let multiFound = items.filter { $0.name.localizedStandardContains(multiSearch) ||
    $0.size.localizedStandardContains(multiSearch)
}

print(multiFound) // Nothing found, expect to see itemA

Also, it has to be able to handle partial words as a user searches, to support winnowing down visible options.

let partialSearch = "stuff l"
let partialFound = items.filter { $0.name.localizedStandardContains(partialSearch) ||
    $0.size.localizedStandardContains(partialSearch)
}

print(partialFound) // Nothing found, expect to see itemA

I suspect I may need to split the search term up into an array and process each word individually and see what the result is from the combined check. My concern is that the actual implementation has far more fields, so this could be impractical.

CodeBender
  • 35,668
  • 12
  • 125
  • 132

1 Answers1

1

As a fast solution you can do following:

let multiSearch = "st la"
let trimmed = multiSearch.trimmingCharacters(in: .whitespacesAndNewlines)
let multiSearchComponents = trimmed.components(separatedBy: " ")

var filtered = items
multiSearchComponents.forEach { searchTerm in
    filtered = filtered.filter { item in
        item.name.localizedStandardContains(searchTerm) || item.size.localizedStandardContains(searchTerm)
    }
}

print(filtered) //Prints itemA
arturdev
  • 10,884
  • 2
  • 39
  • 67
  • Thanks, your answer works under almost every condition, except when I have "st ", which produces a space that clears the array. The solution for this is to add .filter { !$0.isEmpty } to the end of the separatedBy statement (which came from a different answer by Leo) – CodeBender Mar 05 '18 at 15:14
  • @CodeBender if you would like to search every word in the string better to use enumerateSubstrings byWords. It works also if you have punctuation and/or spaces in your string https://stackoverflow.com/a/30679914/2303865 – Leo Dabus Mar 05 '18 at 15:29