Individual Sort in NSFetchedResultsController

After spending hours, I found that the NSFetchedResultsController supported by SQLite was not able to do the individual sorting from the next article.

Custom Sort NSFetchedResultsController Doesn't Get

However, I could not find the actual solution to my problem.

Here is what I am trying to do.

Background:
I have an English dictionary database (just a simple list of words - very large) in CoreData. Words are displayed in a UITableView using the NSFetchedResultsController.

UITableView has an associated search bar. When a user enters a string in the search bar, the UITableView displays a list of filtered words.

Why do I need individual sorting:
When the user enters a string, suppose it was bre , I change it to a regular expression, b.*r.*e.* R. b.*r.*e.* E. b.*r.*e.* And use it as an NSPredicate, and then execute the Fetch function. That all words like "naked" and "gap" were displayed in the form of a table.

By default, words are displayed in alphabetical order. Therefore, bare will be earlier break .

I want break to come before bare in the search list because the first three characters of break exactly match what the user enters.

Possible ideas:

  • Copy the result of NSFetchedResultsController to NSArray and do custom sorting. I'm not sure how fast NSArray will work for a large array, such as an English dictionary.
  • Try executing Fetch several times. For example, above, try executing bre.* for bre.* , br.+e.* bre.* br.+e.* , b.+r.+e.* bre.* b.+r.+e.* In order and combine them.

Both ideas do not look very neat.

I appreciate if you can offer any known neat and typical solution to this kind of problem.

+4
source share
2 answers

Another approach you can consider is to use the transient property to decorate the results to indicate the type of match, and then use this transient property as the first sort descriptor.

To do this, iterate through all the results, compare the strings again, and set the attributes. If you expect a large set of results, using an array can be just as simple.

If you need to efficiently handle large result sets, I would suggest using two sort descriptors, one of which returns only exact matches, and the other only inaccurate matches. Then display the results from the first, and then the results of the second. With a compound predicate to be achieved.

+1
source

Wow, this problem was annoying.

My setup is as follows. I have a search that takes input and searches for users by matching username or full name. The server has already returned the appropriate order, but since I am using NSFetchedResultsController, I need some sort descriptor. Here is what I did, it seems to work well. I added a new property to my custom object called matchScore , and during CRUD from the server I get a score of t21> Levenshtein Distance between query ↔ username and query ↔ full name

Now I have a sort descriptor that will order by the closest matching results from the server with the user request. The code is Rubybotiv, but should be readable.

 sortDescriptors = [] sortDescriptors << NSSortDescriptor.sortDescriptorWithKey("matchScore", ascending:true) 

With the new sort descriptor, I can now get the β€œless than perfect” results and still stick to the closest matches. Now I can avoid some potential @Jaemin solutions that included complex aggregation of results to get around non-standard views that don't work.

 request.predicate = NSPredicate.predicateWithFormat("(username MATCHES[cd] %@) OR (username BEGINSWITH[cd] %@) OR (name CONTAINS[cd] %@)", argumentArray:[searchString, searchString, searchString]) 

A compliance account is now generated on the CRUD from the server.

 usersContext.performBlock(lambda{ restUsers.each do |restUser| user = User.entityWithRestModel(restUser, usersContext) user.matchScore = [query.compareWithWord(user.username, matchGain:10, missingCost:1), query.compareWithWord(user.name, matchGain:10, missingCost:1].min puts "u:#{user.username} <-> q:#{query} score:#{user.matchScore}" end }) 

Here is the NSString category that I use to get Levenshtein distance. https://gist.github.com/iloveitaly/1515464

0
source

All Articles