Сравнение массива с другим с помощью NSPredicate - PullRequest
1 голос
/ 22 марта 2012

У меня следующая структура:

TxnSummary * t1 = [[TxnSummary alloc] init];
t1.txnId = @"1";
t1.shortDesc = @"First one";
t1.filters = [[NSArray alloc] initWithObjects:@"F1", @"F2", nil];

TxnSummary * t2 = [[TxnSummary alloc] init];
t2.txnId = @"2";
t2.shortDesc = @"Second one";
t2.filters = [[NSArray alloc] initWithObjects:@"F1",@"F2", @"F3", nil];

TxnSummary * t3 = [[TxnSummary alloc] init];
t3.txnId = @"3";
t3.shortDesc = @"Third one";
t3.filters = [[NSArray alloc] initWithObjects:@"F1", @"F3", nil];

TxnSummary * t4 = [[TxnSummary alloc] init];
t4.txnId = @"4";
t4.shortDesc = @"Fourth one";
t4.filters = [[NSArray alloc] initWithObjects:@"F4", nil];

NSArray * xnArray = [[NSArray alloc] initWithObjects:t1,t2,t3,t4, nil];

Теперь, если я хочу выяснить, какие из сводок txn имеют фильтры F1, я мог бы сделать это:

NSPredicate * predicate = [NSPredicate predicateWithFormat:@"filters CONTAINS[cd] %@", @"F1"];
NSArray * filteredArray = [xnArray filteredArrayUsingPredicate:predicate];

Это хорошо работает, если я сравниваю только одну строку, но если я хочу выяснить, какие из всех сводок txn имеют фильтры "F1" или "F2", тогда, если мне придется следовать вышеуказанному механизму, у меня создать два предиката - каждый для F1 и F2, а затем запустить его для xnArray (который кажется неэффективным). Я хочу иметь возможность создать список строк фильтров и использовать его для получения соответствующих txs из массива xn.

NSArray * filterStrings = [[NSArray alloc] initWithObjects:@"F1",@"F2", nil];

Имеет ли NSPredicate функциональность для достижения этой цели или мне следует прибегнуть к какому-либо другому методу фильтрации?

Ценю вашу помощь.

Спасибо, Кумар

Ответы [ 4 ]

4 голосов
/ 22 марта 2012

Если я вас правильно понимаю, вы можете достичь этого, создав составной предикат из массива предикатов, например:

 NSPredicate *newFilterPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:selectedItemIDs];

РЕДАКТИРОВАТЬ: добавлено более подробное объяснение:

Составные предикаты объединяют предикаты в один предикат. Например, если вы хотите отфильтровать элементы, содержащие «F1» или «F2», вы делаете это:

// Normally build this in some kind of loop
NSPredicate *firstPredicate = [NSPredicate predicateWithFormat:@"filter =%@", @"F1"];
NSPredicate *secondPredicate = [NSPredicate predicateWithFormat:@"filter =%@", @"F1"];

// Create the array of predicates
NSArray *arrayOfPredicates = [NSArray arrayWithObjects:firstPredicate, secondPredicate, nil];

// Create the compound predicate
NSPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:arrayOfPredicates];

Существуют также методы для «и» вместо «или», а также другие логические условия. Полная ссылка может быть найдена здесь: Ссылка класса NSCompoundPredicate

Надеюсь, это поможет,

Dave

3 голосов
/ 22 марта 2012

Вы можете сделать что-то вроде:

NSPredicate * predicate = [NSPredicate predicateWithFormat:@"filters CONTAINS[cd] %@ || filters CONTAINS[cd] %@", @"F1", @"F4"];

Если вы хотите добавить все ключи в массиве, вы можете сделать что-то вроде этого:

NSArray * filterStrings = [[NSArray alloc] initWithObjects:@"F1",@"F4", nil];

NSString* predicateString = [filterStrings componentsJoinedByString:@"'|| filters CONTAINS[cd] '"];
predicateString = [NSString stringWithFormat:@"filters CONTAINS[cd] '%@'",predicateString];


NSPredicate * predicate = [NSPredicate predicateWithFormat:predicateString];
NSArray * filteredArray = [xnArray filteredArrayUsingPredicate:predicate];
1 голос
/ 22 марта 2012

Я бы не использовал NSArray для хранения фильтров. Это прекрасный книжный пример использования NSSet / NSMutableSet . Вы можете инициализировать аналогично массиву:

t1.filters = [[NSSet alloc] initWithObjects:@"F1", @"F2", nil];

Затем вы проверяете, существует ли эта конкретная строка, просто вызывая:

BOOL contains = [t1.filter containsObject:@"F1"];

Теперь вы также можете фильтровать набор такими методами, как filteredSetUsingPredicate, objectsPassingTest (для использования с блоками) или даже создавать пересечения или объединения с другими наборами (isSubsetOfSet, intersectsSet и т. Д.). Например, вы можете создать новый набор с найденными элементами и проверить, содержит ли он их:

NSSet* toFind = [[NSSet alloc] initWithObjects:@"F1", @"F3", nil];
[toFind isSubsetOfSet:t1.filters];

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

0 голосов
/ 22 марта 2012

Если точное соответствие в порядке, вы можете использовать предикат IN следующим образом:

NSArray *filterStrings = [NSArray arrayWithObjects:@"F1", @"F2", nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"filters IN %@", filterStrings];

NSArray *filteredArray = [xnArray filteredArrayUsingPredicate:predicate];
...