Настраиваемая сортировка в NSFetchedResultsController - PullRequest
4 голосов
/ 16 октября 2011

Потратив часы, я обнаружил, что в NSFetchedResultsController, поддерживаемом SQLite из следующей статьи, невозможно выполнить настраиваемую сортировку.

NSFetchedResultsController Не сортируется настраиваемая сортировка

Однако я не смог найти реальное решение для моей проблемы.

Вот что я пытаюсь сделать.

Справочная информация:
У меня есть словарь английского языкаБаза данных (просто простой список слов - очень большой) в CoreData.Слова отображаются в UITableView с использованием NSFetchedResultsController.

UITableView имеет связанную панель поиска.Когда пользователь вводит строку в строке поиска, UITableView показывает список отфильтрованных слов.

Зачем мне настраивать сортировку:
Когда пользователь вводит строку, скажем,было bre, я изменяю его на регулярное выражение b.*r.*e.* и использую его как NSPredicate, затем выполняю executeFetch.Таким образом, все слова, такие как «bare» и «break», будут отображаться в табличном представлении.

По умолчанию слова отображаются в алфавитном порядке.Поэтому bare будет предшествовать break.

Я хочу, чтобы break предшествовал bare в списке поиска, потому что первые три символа break точно совпадают с тем, что вводил пользователь.

Возможные идеи:

  1. Скопируйте результат NSFetchedResultsController в NSArray и выполните пользовательскую сортировку.Я не уверен, насколько быстро NSArray будет работать для большого массива, такого как словарь английского языка.
  2. Попробуйте выполнить executeFetch несколько раз.Например, попробуйте выполнить executeFetch для bre.*, br.+e.*, b.+r.+e.* по порядку и объедините их.

Обе идеи выглядят не очень аккуратно.

Я ценюесли вы можете предложить какое-либо известное аккуратное и типичное решение для такого рода проблем.

Ответы [ 2 ]

1 голос
/ 17 мая 2012

Другой подход, который вы могли бы рассмотреть, - это использование переходного свойства для декорирования результатов, чтобы указать тип соответствия, а затем использование этого переходного свойства в качестве дескриптора первой сортировки.

Это требует циклического перебора всех результатов,снова сравниваем строки и устанавливаем атрибуты.Если вы ожидаете длинный набор результатов, использование массива может быть таким же простым.

Если вам нужно эффективно обрабатывать большие наборы результатов, я бы предложил использовать два дескриптора сортировки, один из которых возвращает только точные совпадения,и другой, который возвращает только неточные совпадения.Затем отобразите результаты первого, а затем результаты второго.С составным предикатом, который должен быть возможен.

0 голосов
/ 20 июля 2014

Ух ты, эта проблема раздражала.

Моя настройка следующая. У меня есть поиск, который принимает входные данные и ищет пользователей, сопоставляя имя пользователя или полное имя. Сервер уже возвращал соответствующий порядок, но так как я использую NSFetchedResultsController, мне нужен некоторый дескриптор сортировки. Вот то, что я сделал, что, кажется, работает хорошо. Я добавил новое свойство в свой пользовательский объект с именем matchScore, и во время CRUD с сервера я получаю оценку MIN() Левенштейновского расстояния между запросом <-> имя пользователя и запросом <-> полное имя

Теперь у меня есть дескриптор сортировки, который упорядочит по ближайшему совпадению результаты с сервера с запросом пользователя. Код 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
})

Вот категория NSString, которую я использую, чтобы получить расстояние Левенштейна. https://gist.github.com/iloveitaly/1515464

...