Вопрос

у меня есть 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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top