NSPredicate 'OR' фильтрация на основе NSArray ключей

Рассмотрим следующий NSArray:

NSArray *dataSet = [[NSArray alloc] initWithObjects:
                 [NSDictionary dictionaryWithObjectsAndKeys:@"abc", @"key1", @"def", @"key2", @"hij", @"key3", nil], 
                 [NSDictionary dictionaryWithObjectsAndKeys:@"klm", @"key1", @"nop", @"key2", nil], 
                 [NSDictionary dictionaryWithObjectsAndKeys:@"qrs", @"key2", @"tuv", @"key4", nil], 
                 [NSDictionary dictionaryWithObjectsAndKeys:@"wxy", @"key3", nil], 
                 nil];

Я могу отфильтровать этот массив, чтобы найти объекты словаря, содержащие ключ key1

// Filter our dataSet to only contain dictionary objects with a key of 'key1'
NSString *key = @"key1";
NSPredicate *key1Predicate = [NSPredicate predicateWithFormat:@"%@ IN self.@allKeys", key];
NSArray *filteretSet1 = [dataSet filteredArrayUsingPredicate:key1Predicate];
NSLog(@"filteretSet1: %@",filteretSet1);

Что соответственно возвращает:

filteretSet1: (
        {
        key1 = abc;
        key2 = def;
        key3 = hij;
    },
        {
        key1 = klm;
        key2 = nop;
    }
)

Теперь я хочу отфильтровать набор данных для объектов словаря, содержащих ЛЮБОЙ из ключей в NSArray.

Например, используя массив: NSArray *keySet = [NSArray arrayWithObjects:@"key1", @"key3", nil];, я хочу создать предикат, который возвращает и массив any словарных объектов, содержащих либо 'key1' , либо 'key3' (т. Е. В в этом примере будут возвращены все объекты словаря, за исключением третьего объекта, поскольку он не содержит ни 'key1' , ни 'key3').

Есть идеи о том, как я этого добьюсь? Придется ли мне использовать составной предикат?


person So Over It    schedule 20.06.2012    source источник


Ответы (3)


Оператор ANY в NSPredicate охватывает это:

NSSet *keys = [NSSet setWithObjects:@"key1", @"key3", nil];

NSPredicate *key1Predicate = [NSPredicate predicateWithFormat:@"any self.@allKeys in %@", keys];
person Monolo    schedule 20.06.2012
comment
any - вот чего мне не хватало. Я не знаю, почему мне так сложно понять NSPredicate. Спасибо за Ваш ответ. Моноло +1 :) - person So Over It; 20.06.2012
comment
это чувствительно к регистру? В конце концов я узнаю, но надеюсь, что это уже произошло. Я прокомментирую позже. - person coolcool1994; 21.12.2013
comment
@ coolcool1994 ANY и IN (и SELF) в приведенном выше предикате не чувствительны к регистру (на самом деле я часто пишу их заглавными буквами, чтобы выделить их), имена ключей / методов таковы, поэтому @allKeys is с учетом регистра. - person Monolo; 21.12.2013
comment
Хорошо, это не чувствительно к регистру. Спасибо! - person coolcool1994; 22.12.2013

Сделай это:

   NSString *key = @"key1";
   NSString *key1 = @"key3";
   NSPredicate *key1Predicate = [NSPredicate predicateWithFormat:@"%@ IN self.@allKeys OR %@ IN self.@allKeys",key,key1];
   NSArray *filteretSet1 = [dataSet filteredArrayUsingPredicate:key1Predicate];
   NSLog(@"filteretSet1: %@",filteretSet1);

У меня отлично работает. Надежда полезная

person Paresh Navadiya    schedule 20.06.2012
comment
Спасибо за ваш вклад. Я знаю, что могу использовать ИЛИ. Причина, по которой я хотел использовать массив, заключалась в том, чтобы использовать любое количество ключей, а не ровно 2 ключа. - person So Over It; 20.06.2012

Хотя на вопрос был дан ответ, вы также можете использовать блок для большей детализации:

NSArray *filter = [NSArray arrayWithObjects:@"key1", @"key3",nil];

NSPredicate *filterBlock = [NSPredicate predicateWithBlock: ^BOOL(id obj, NSDictionary *bind){        
    NSDictionary *data = (NSDictionary*)obj;

    // use 'filter' and implement your logic and return YES or NO
}];

[dataSet filteredArrayUsingPredicate:filterBlock];

Это можно переставить по своему усмотрению, возможно, в рамках собственного метода.

person Leonardo    schedule 20.06.2012