Johnny Rockex
Johnny Rockex

Reputation: 4196

Improve search performance in objective-c

I am searching through around 100k strings in a function:

results = [NSMutableArray new];
for (int n = 0; n < (int)_donkey.searchStrings.count; n++){
    if ([[_donkey.searchStrings[n] lowercaseString] rangeOfString:tf.text.lowercaseString].location != NSNotFound){
        [results addObject:_donkey.formattedStrings[n]];
    }
}

where tf.text is the user inputted text in a UITextField. Performance is slow and I get the impression there is a better way of searching rather than a straight up string comparison anyway.

The strings being searched through are formatted like this: "attributeA attributeB attributeC", so if attributeB is entered before attributeA, it does not come up as a result, which it should.

Upvotes: 0

Views: 155

Answers (1)

Ken Thomases
Ken Thomases

Reputation: 90531

A few obvious things:

  • Don't call the searchStrings property getter multiple times through the loop. Call it once and cache it in a local variable.
  • Don't call the count getter on every loop iteration.
  • Don't call the text getter on every loop iteration.
  • If you're going to use lowercaseString, don't call it on the text field's string on every loop iteration. But see the next item.
  • Don't use lowercaseString. Use -rangeOfString:options: and the NSCaseInsensitiveSearch option, -localizedCaseInsensitiveContainsString:, or -localizedStandardContainsString:. Not only are they likely to be faster, they're more correct. (Languages can be strange and comparing lowercased strings may not necessarily be the same as a case-insensitive comparison.)
  • Since you're building an array from the indexes of the matching elements of searchStrings, you can use -indexesOfObjectsWithOptions:passingTest: to build a set of the indexes of the matching elements. You don't have to write the (slower) enumeration code yourself in that case. You can also specify NSEnumerationConcurrent in the options to allow the framework to use multiple threads to perform the search. After you have the index set, you would then use -objectsAtIndexes: to get an array of the corresponding elements from formattedStrings. Again, the framework can do that faster than your approach of building it up one element at a time in a mutable array. (Thanks to @rmaddy for the suggestion.)

The strings being searched through are formatted like this: "attributeA attributeB attributeC", so if attributeB is entered before attributeA, it does not come up as a result, which it should.

I don't understand this part of your question and it seems like it's about correctness and not performance. So: 1) get correctness first before being concerned about performance. No point making a wrong algorithm faster. 2) It should be a separate question.

Upvotes: 2

Related Questions