Статьи

Использование NSPredicate для фильтрации данных

Фильтрация данных является одной из важнейших задач в вычислительной технике. Имея все данные, доступные сегодня, нам нужно применить определенные ограничения и ограничения, чтобы фактически сделать их пригодными для использования. Какая польза от возможности прокручивать список буквально тысяч элементов списка, когда вы действительно заботитесь об одном или двух из них? Фильтрация и поиск информации составляют значительную часть нашего рабочего дня — каждый раз, когда вы используете Google, вы применяете фильтр к огромному набору данных, которые мы называем Интернетом.

Даже на локальном компьютере вы постоянно используете такие службы, как Spotlight или поле поиска в почтовом приложении. Приложения, в которых отсутствуют достойные возможности поиска и фильтрации, иногда очень сложны в использовании, поэтому разработчикам следует потратить некоторое время на размышления о том, как позволить пользователям фильтровать данные, с которыми они имеют дело.

В этом посте я собираюсь сосредоточиться на способах фильтрации данных. Мы не будем рассматривать сторону пользовательского интерфейса — это то, что я сделаю в следующем сообщении в блоге.

Старая школа фильтрации

Если вы посмотрите на произвольную кодовую базу, скорее всего, вы рано или поздно столкнетесь с фрагментом кода, похожим на этот:

NSMutableArray *oldSkoolFiltered = [[NSMutableArray alloc] init];
for (Book *book in bookshelf) {
if ([book.publisher isEqualToString:@"Apress"]) {
[oldSkoolFiltered addObject:book];
}
}

Это простой подход к фильтрации массива элементов (в данном случае речь идет о книгах) с использованием довольно простого оператора if. В этом нет ничего плохого, но, несмотря на то, что мы используем здесь довольно простое выражение, код довольно многословен. Мы можем легко представить, что произойдет, если нам понадобится более сложный критерий выбора или комбинация критериев фильтрации.

Простая фильтрация с NSPredicate

Благодаря Какао мы можем упростить код, используя NSPredicate . NSPredicate — это объектное представление оператора if или, более формально, предиката.

Предикаты — это выражения, которые оценивают значение истинности , то есть истинное или ложное. Мы можем использовать их для проверки и фильтрации. В Какао мы можем использовать NSPredicate для оценки отдельных объектов, фильтрации массивов и выполнения запросов к наборам данных Core Data.

Давайте посмотрим, как выглядит наш пример при использовании NSPredicate:

NSPredicate *predicate =
[NSPredicate predicateWithFormat:@"publisher == %@", @"Apress" ];
NSArray *filtered = [bookshelf filteredArrayUsingPredicate:predicate];

Гораздо короче и лучше читаемо!

Фильтрация с помощью регулярных выражений

Регулярные выражения могут использоваться для решения практически любой проблемы,;-) поэтому полезно знать, что вы можете использовать их и в NSPredicates. Чтобы использовать регулярные выражения в вашем NSPredicate, вам нужно использовать оператор MATCHES.

Давайте отфильтруем все книги, посвященные программированию для iPad или iPhone:

predicate = [NSPredicate predicateWithFormat:@"title MATCHES '.*(iPhone|iPad).*'"];
filtered = [bookshelf filteredArrayUsingPredicate:predicate];
dumpBookshelf(@"Books that contain 'iPad' or 'iPhone' in their title", filtered);

При использовании регулярных выражений в NSPredicate необходимо соблюдать некоторые правила: самое главное, вы не можете использовать метасимволы регулярных выражений внутри набора шаблонов .

Фильтрация с использованием операций над множествами

Давайте на минутку предположим, что вы хотите отфильтровать все книги, которые были опубликованы вашими любимыми издателями. Используя оператор IN, это довольно просто: во-первых, нам нужно настроить набор, содержащий интересующие нас издатели. Затем мы можем создать предикат и, наконец, выполнить операцию фильтрации:

NSArray *favoritePublishers = [NSArray arrayWithObjects:@"Apress", @"O'Reilly", nil];
predicate = [NSPredicate predicateWithFormat:@"publisher IN %@", favoritePublishers];
filtered = [bookshelf filteredArrayUsingPredicate:predicate];
dumpBookshelf(@"Books published by my favorite publishers", filtered);

Усовершенствованная фильтрация благодаря доброте KVC

NSPredicate использует кодирование ключ-значение для достижения своей цели. С одной стороны, это означает, что ваши классы должны быть совместимы с KVC , чтобы их можно было запрашивать с помощью NSPredicate (по крайней мере, тех атрибутов, которые вы хотите запросить). С другой стороны, это позволяет нам выполнять очень интересные вещи с небольшими строками кода.

Давайте для примера возьмем список книг, написанных авторами с именем «Марк»:

predicate =
[NSPredicate predicateWithFormat:@"authors.lastName CONTAINS %@", @"Mark" ];
filtered = [bookshelf filteredArrayUsingPredicate:predicate];

В случае, если мы хотим вернуть значение одной из агрегатных функций, нам не нужно использовать сам NSPredicate, а вместо этого использовать непосредственно KVC. Давайте вернем среднюю цену всех книг на нашей полке:

NSNumber *average = [bookshelf valueForKeyPath:@"@avg.price"];

Вывод

Библиотеки Какао предоставляют некоторые очень мощные абстракции, которые могут сделать вашу жизнь и жизнь людей, читающих ваш код, намного проще. О них стоит знать, так что продолжайте просматривать документацию по Какао и отыщите эти драгоценные камни!

Руководство по программированию NSPredicate от Apple содержит подробную документацию по NSPredicate, содержащую все то, о чем я не рассказывал в этом посте.

NSPredicate также играет важную роль при запросе данных в Core Data, о чем нам нужно будет узнать в одной из следующих публикаций блога. Оставайтесь в курсе!

Код

Код для этого поста доступен на моей странице GitHub: получить разветвление !

 

С http://www.peterfriese.de/using-nspredicate-to-filter-data/