花了好几个小时之后,我发现在以下文章中不可能在SQLite支持的NSFetchedResultsController中进行自定义排序。
NSFetchedResultsController custom sort not getting called
但是,我无法找到解决问题的实际方法。
这就是我想要做的事情。
背景
我在CoreData中有一个英文字典数据库(只是一个简单的单词列表 - 非常大)。使用NSFetchedResultsController在UITableView中显示单词。
UITableView有一个关联的搜索栏。当用户在搜索栏中输入字符串时,UITableView会显示已过滤的单词列表。
为什么我需要自定义排序:
当用户输入一个字符串时,假设它是bre
,我将其更改为正则表达式b.*r.*e.*
并将其用作NSPredicate,然后执行performFetch。因此,所有像'bare'和'break'这样的单词都会显示在表格视图中。
默认情况下,单词显示为字母顺序。因此,bare
将在break
之前出现。
我希望break
在bare
之前到达搜索列表,因为break
的前三个字符与用户输入完全匹配。
可能的想法:
bre.*
,br.+e.*
,b.+r.+e.*
的performFetch并合并它们。这两种想法看起来都不太整洁。
如果你能提出任何已知的整洁和优秀的话,我感激不尽。解决这类问题的典型方法。
答案 0 :(得分:1)
您可以考虑的另一种方法是使用transient属性来修饰结果以指示匹配的类型,然后将该transient属性用作第一个排序描述符。
这需要循环遍历所有结果,再次比较字符串并设置属性。如果您期望得到很长的结果,那么使用数组可能同样容易。
如果你需要有效地处理大型结果集,我建议使用两个排序描述符,一个只返回完全匹配,另一个只返回非完全匹配。然后显示第一个结果,然后显示第二个结果。使用复合谓词,应该可以完成。
答案 1 :(得分:0)
我的设置如下。我有一个搜索,它接受输入并通过匹配用户名或全名来查找用户。服务器已经返回了相应的顺序,但由于我正在使用NSFetchedResultsController,我需要一些排序描述符这是我做的,似乎运行良好。我向我的用户实体添加了一个名为matchScore
的新属性,在服务器的CRUD中,我得到了查询< - >之间的MIN()
Levenshtein距离得分。用户名和查询< - >全名
我现在有一个排序描述符,它将按照服务器与用户查询最接近的匹配结果排序。代码是rubymotion,但应该仍然可读。
sortDescriptors = []
sortDescriptors << NSSortDescriptor.sortDescriptorWithKey("matchScore", ascending:true)
使用新的排序描述符,我现在可以获取“不太理想”的结果,并且仍然保持最接近的匹配。我现在可以避免一些@ Jaemin的潜在解决方案,这些解决方案涉及复杂的结果聚合,以避免自定义排序不起作用。
request.predicate = NSPredicate.predicateWithFormat("(username MATCHES[cd] %@) OR (username BEGINSWITH[cd] %@) OR (name CONTAINS[cd] %@)", argumentArray:[searchString, searchString, searchString])
现在从服务器在CRUD上生成匹配分数。
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
})
以下是我用来获取Levenshtein距离的NSString
类别。 https://gist.github.com/iloveitaly/1515464