фильтрация NSArray в новый NSArray в объекте-c
-
02-07-2019 - |
Вопрос
у меня есть NSArray
и я хотел бы создать новый NSArray
с объектами из исходного массива, отвечающими определенным критериям.Критерии определяются функцией, которая возвращает BOOL
.
я могу создать NSMutableArray
, перебрать исходный массив и скопировать объекты, которые принимает функция фильтра, а затем создать его неизменяемую версию.
Есть ли способ лучше?
Решение
NSArray
и NSMutableArray
предоставить методы для фильтрации содержимого массива. NSArray
обеспечивает фильтредаррайусингпредикат: который возвращает новый массив, содержащий объекты в получателе, соответствующие указанному предикату. NSMutableArray
добавляет фильтрусинпредикат: который оценивает содержимое получателя по указанному предикату и оставляет только соответствующие объекты.Эти методы проиллюстрированы в следующем примере.
NSMutableArray *array =
[NSMutableArray arrayWithObjects:@"Bill", @"Ben", @"Chris", @"Melissa", nil];
NSPredicate *bPredicate =
[NSPredicate predicateWithFormat:@"SELF beginswith[c] 'b'"];
NSArray *beginWithB =
[array filteredArrayUsingPredicate:bPredicate];
// beginWithB contains { @"Bill", @"Ben" }.
NSPredicate *sPredicate =
[NSPredicate predicateWithFormat:@"SELF contains[c] 's'"];
[array filteredArrayUsingPredicate:sPredicate];
// array now contains { @"Chris", @"Melissa" }
Другие советы
Есть множество способов сделать это, но, безусловно, самым простым является использование [NSPredicate predicateWithBlock:]
:
NSArray *filteredArray = [array filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *bindings) {
return [object shouldIKeepYou]; // Return YES for each object you want in filteredArray.
}]];
Я думаю, это настолько кратко, насколько это возможно.
Быстрый:
Для тех, кто работает с NSArray
в Swift, вы можете предпочесть это даже больше краткая версия:
nsArray = nsArray.filter { $0.shouldIKeepYou() }
filter
это просто метод Array
(NSArray
неявно связан со Свифтом Array
).Требуется один аргумент:замыкание, которое принимает один объект из массива и возвращает Bool
.В конце просто вернитесь true
для любых объектов, которые вы хотите включить в отфильтрованный массив.
Если у вас OS X 10.6/iOS 4.0 или новее, вам, вероятно, лучше использовать блоки, чем NSPredicate.Видеть -[NSArray indexesOfObjectsPassingTest:]
или напишите свою собственную категорию, чтобы добавить удобную -select:
или -filter:
метод (пример).
Хотите, чтобы кто-нибудь другой написал эту категорию, протестировал ее и т. д.?Проверить БлокиКомплект (документы массива).И здесь много больше примеров можно найти, скажем, выполнив поиск, например. "выбор категории блока nsarray".
Основываясь на ответе Клея Бриджеса, вот пример фильтрации с использованием блоков (измените yourArray
к имени переменной массива и testFunc
к имени вашей функции тестирования):
yourArray = [yourArray objectsAtIndexes:[yourArray indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return [self testFunc:obj];
}]];
Предполагая, что все ваши объекты относятся к одному типу, вы можете добавить метод в качестве категории их базового класса, который вызывает функцию, которую вы используете для ваших критериев.Затем создайте объект NSPredicate, который ссылается на этот метод.
В какой-то категории определите свой метод, который использует вашу функцию
@implementation BaseClass (SomeCategory)
- (BOOL)myMethod {
return someComparisonFunction(self, whatever);
}
@end
Затем, где бы вы ни проводили фильтрацию:
- (NSArray *)myFilteredObjects {
NSPredicate *pred = [NSPredicate predicateWithFormat:@"myMethod = TRUE"];
return [myArray filteredArrayUsingPredicate:pred];
}
Конечно, если ваша функция сравнивается только со свойствами, доступными из вашего класса, возможно, будет проще преобразовать условия функции в строку предиката.
NSPredicate
это способ создания условия для фильтрации коллекции в nextstep (NSArray
, NSSet
, NSDictionary
).
Например, рассмотрим два массива arr
и filteredarr
:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",@"c"];
filteredarr = [NSMutableArray arrayWithArray:[arr filteredArrayUsingPredicate:predicate]];
в отфильтрованном дарре наверняка будут элементы, содержащие только символ c.
чтобы было легко запомнить тем, у кого мало опыта работы с sql, это
*--select * from tbl where column1 like '%a%'--*
1)выбрать * из таблицы --> коллекция
2) столбец 1 типа «%a%» --> NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",@"c"];
3) выберите * из таблицы, где столбец 1, например '%a%' -->
[NSMutableArray arrayWithArray:[arr filteredArrayUsingPredicate:predicate]];
надеюсь, это поможет
NSArray+X.h
@interface NSArray (X)
/**
* @return new NSArray with objects, that passing test block
*/
- (NSArray *)filteredArrayPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate;
@end
NSArray+X.m
@implementation NSArray (X)
- (NSArray *)filteredArrayPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate
{
return [self objectsAtIndexes:[self indexesOfObjectsPassingTest:predicate]];
}
@end
Оформить заказ в этой библиотеке
https://github.com/BadChoice/Collection
Он поставляется с множеством простых функций массива, чтобы никогда больше не писать цикл.
Итак, вы можете просто сделать:
NSArray* youngHeroes = [self.heroes filter:^BOOL(Hero *object) {
return object.age.intValue < 20;
}];
или
NSArray* oldHeroes = [self.heroes reject:^BOOL(Hero *object) {
return object.age.intValue < 20;
}];
Лучший и простой способ — создать этот метод и передать массив и значение:
- (NSArray *) filter:(NSArray *)array where:(NSString *)key is:(id)value{
NSMutableArray *temArr=[[NSMutableArray alloc] init];
for(NSDictionary *dic in self)
if([dic[key] isEqual:value])
[temArr addObject:dic];
return temArr;
}