Використання NSPredicate для фільтрації NSArray на основі ключів NSDictionary


94

У мене є безліч словників.

Я хочу відфільтрувати масив на основі ключа.

Я спробував це:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(SPORT ==  %@)", @"Football"];

NSArray *filteredArray = [data filteredArrayUsingPredicate:predicate];

Це не працює, я не отримую результатів. Я думаю, що роблю щось не так. Я знаю, що це метод, якщо "СПОРТ" був іваром. Я думаю, що це, мабуть, інакше, якщо це ключ.

Однак я не зміг знайти приклад.

Дякую


Оновлення

Я додав лапки навколо рядка, який я шукаю.

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(SPORT ==  '%@')", @"Football"];

Це все ще не працює.


Оновлення 2

Вирішив це. Мені фактично довелося видалити одинарні лапки, що, здається, суперечить тому, що каже керівництво.

Моя справжня проблема полягає в тому, що у мене був вкладений масив, і я фактично не оцінював словники. Рух кісткової голови.


Зазначимо лише, що предикат за замовчуванням чутливий до регістру (використовуйте [c], щоб отримати нечутливий).
groumpf

Відповіді:


151

Це повинно працювати - до тих пір, поки змінна даних насправді є масивом, що містить словник із ключем SPORT

NSArray *data = [NSArray arrayWithObject:[NSMutableDictionary dictionaryWithObject:@"foo" forKey:@"BAR"]];    
NSArray *filtered = [data filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"(BAR == %@)", @"foo"]];

У цьому випадку відфільтрований містить словник.

(% @ не потрібно цитувати, це робиться, коли NSPredicate створює об'єкт.)


Чи працює NSPredicate на iPhone? Він чудово працює на симуляторі, але запуск його на iPhone видає помилку, через яку не вдалося знайти клас NSPredicate.
lostInTransit

NSPredicate доступний з iOS 3.0.
зекель

1
для уточнення для таких кодерів, як я, ключовим рядком коду є 'NSArray * filtered = [data filteredArrayUsingPredicate: [NSPredicate predicateWithFormat: @ "(BAR ==% @)", @ "foo"]];' де 'data' - це масив nsdictionaries, який вже є у вашому коді. (спасибі вам suraken)
tmr

Що робити, якщо імена ключів динамічні?
iPeter

27

Я знаю, що це старі новини, але додати свої два центи. За замовчуванням я використовую команди, LIKE[cd]а не просто [c]. [d]Порівнює букви з діакритичними символами. Це особливо добре працює в моєму додатку Warcraft, де люди пишуть своє ім'я "Vòódòó", що робить майже неможливим пошук свого імені в табличному поданні. [d]Смуги їх символи наголоси у предикате. Отже, присудок @"name LIKE[CD] %@", object.nameдеobject.name == @"voodoo" поверне об’єкт, що містить ім’я Vòódòó.

З документації Apple: like [cd] означає "нечутливий до регістру та діакритики like.") Повний опис синтаксису рядка та перелік усіх доступних операторів див . У Синтаксис рядка формату предикатів .


11
#import <Foundation/Foundation.h>
// clang -framework Foundation Siegfried.m 
    int
main() {
    NSArray *arr = @[
        @{@"1" : @"Fafner"},
        @{@"1" : @"Fasolt"}
    ];
    NSPredicate *p = [NSPredicate predicateWithFormat:
        @"SELF['1'] CONTAINS 'e'"];
    NSArray *res = [arr filteredArrayUsingPredicate:p];
    NSLog(@"Siegfried %@", res);
    return 0;
}

3

NSPredicate доступний лише в iPhone 3.0.

Ви цього не помітите, поки не спробуєте запустити на пристрої.


0

За допомогою Swift 3, коли ви хочете відфільтрувати масив словників із предикатом на основі ключів та значень словника, ви можете вибрати один із наведених нижче шаблонів.


№1. ВикористанняNSPredicate init(format:arguments:) ініціалізатора

Якщо ви походите з Objective-C, init(format:arguments:) пропонує стиль кодування ключ-значення для оцінки вашого предиката.

Використання:

import Foundation

let array = [["key1": "value1", "key2": "value2"], ["key1": "value3"], ["key3": "value4"]]

let predicate = NSPredicate(format: "key1 == %@", "value1")
//let predicate = NSPredicate(format: "self['key1'] == %@", "value1") // also works
let filteredArray = array.filter(predicate.evaluate)

print(filteredArray) // prints: [["key2": "value2", "key1": "value1"]]

№2. Використання NSPredicate init(block:)ініціалізатора

Як альтернативу, якщо ви віддаєте перевагу строго набраним API, а не строго набраним API, ви можете використовувати init(block:)ініціалізатор.

Використання:

import Foundation

let array = [["key1": "value1", "key2": "value2"], ["key1": "value3"], ["key3": "value4"]]

let dictPredicate = NSPredicate(block: { (obj, _) in
    guard let dict = obj as? [String: String], let value = dict["key1"] else { return false }
    return value == "value1"
})

let filteredArray = array.filter(dictPredicate.evaluate)
print(filteredArray) // prints: [["key2": "value2", "key1": "value1"]]

-1

Дивлячись на посилання NSPredicate , схоже, вам потрібно оточити символу заміни лапками. Наприклад, ваш поточний предикат читає: (SPORT == Football)Ви хочете, щоб він читався (SPORT == 'Football'), тому рядок формату має бути @"(SPORT == '%@')".


Я думав, що саме про це сказано теж. Мабуть, цитати не потрібні. Я не впевнений, для чого саме слід використовувати цитати, у яких говорить "цитати".
Кори Флойд,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.