I have a list of Product
objects which have a property called productName
. For example:
Product(
....
productName: "Red Shirt",
)
Product(
....
productName: "Yellow Scarf",
)
Product(
....
productName: "Trousers",
)
What I want:
- When some one searches for Red Scarf, I need to show both red pants and yellow scarf.
My current algorithm:
class Search {
/*
A hashmap is used to store the products.
Key: productName
Value: Product
*/
final Map<String, Product> _map = Map.fromIterable(
products,
key: (product) => product.productName,
);
List<Product> search(String search) {
List<String> searchWords = search.trim().toLowerCase().split(" ");
List<Product> result = [];
for (int i = 0; i < searchWords.length; i++) {
for (int j = 0; j < products.length; j++) {
if (products[j].productName!.toLowerCase().contains(searchWords[i])) {
result.add(products[j]);
}
}
}
return result.toSet().toList();
}
}
The issue with this algorithm is when I type in Red S
, it shows trousers as well since it has S
in it.
I need to solve this issue.
And what better algorithms can be used to reduce the time complexity?
N.B: The _map doesn't do anything. I just thought I might need it.
Solution 1: Guillaume Roux
The most optimised way would be to use RegExp
, the following code will consider that one of your words must start with one of "search word", for example with Red S
it will search for any words starting with red
or s
:
class Search {
Set<Product> search(String search) {
final searchWords = search.trim().split(" ");
final searchWordsRegExp = searchWords.formatToWordsRegExp();
return products.where((product) {
return product.productName.contains(searchWordsRegExp);
}).toSet();
}
}
extension FormatToWordsRegExpExtension on Iterable<String> {
RegExp formatToWordsRegExp({bool caseSensitive = false}) {
final buffer = StringBuffer();
for (final word in this) {
buffer.write(r'^' + word + r'|\b' + word);
}
return RegExp(buffer.toString(), caseSensitive: caseSensitive);
}
}
Use case
void main() {
final search = Search();
final words = ['Red S', 'red s', 'red', 'yellow', 'tro'];
for (final w in words) {
print('Search for "$w"');
search.search(w).showData();
print('--------------------');
}
}
Output
Search for "Red S"
Red Shirt
Yellow Scarf
--------------------
Search for "red s"
Red Shirt
Yellow Scarf
--------------------
Search for "red"
Red Shirt
--------------------
Search for "yellow"
Yellow Scarf
--------------------
Search for "tro"
Trousers
--------------------