Używanie NSPredicate do filtrowania NSArray na podstawie kluczy NSDictionary

94

Mam szereg słowników.

Chcę przefiltrować tablicę na podstawie klucza.

Próbowałem tego:

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

NSArray *filteredArray = [data filteredArrayUsingPredicate:predicate];

To nie działa, nie mam żadnych wyników. Myślę, że robię coś złego. Wiem, że to metoda, jeśli „SPORT” byłby ivar. Myślę, że jest prawdopodobnie inaczej, jeśli jest to klucz.

Nie udało mi się jednak znaleźć przykładu.

Dzięki


Aktualizacja

Dodałem cudzysłowy wokół szukanego ciągu.

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

Nadal nie działa.


Zaktualizuj 2

Rozwiązałem to. Właściwie musiałem usunąć pojedyncze cudzysłowy, co wydaje się być sprzeczne z tym, co mówi przewodnik.

Moim prawdziwym problemem jest to, że miałem zagnieżdżoną tablicę i tak naprawdę nie oceniałem słowników. Ruch głowy kości.

Corey Floyd
źródło
Wystarczy wspomnieć, że predykat domyślnie rozróżnia wielkość liter (użyj [c], aby uzyskać niewrażliwość).
groumpf

Odpowiedzi:

151

Powinno działać - o ile zmienna data jest w rzeczywistości tablicą zawierającą słownik z kluczem SPORT

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

Filtrowane w tym przypadku zawiera słownik.

(% @ nie musi być cytowany, dzieje się tak, gdy NSPredicate tworzy obiekt).

suraken
źródło
Czy NSPredicate działa na iPhonie? Działa świetnie na karcie SIM, ale uruchomienie jej na iPhonie powoduje błąd, że nie można znaleźć klasy NSPredicate.
lostInTransit
NSPredicate jest dostępny od iOS 3.0.
zekel
1
aby wyjaśnić nowym programistom, takim jak ja, kluczową linią kodu jest „NSArray * filter = [data filterArrayUsingPredicate: [NSPredicate predicateWithFormat: @" (BAR ==% @) ", @" foo "]]; ' gdzie „dane” to tablica nsarray z nsdictionaries, która jest już w kodzie. (dziękuję suraken)
tmr
A jeśli nazwy kluczy są dynamiczne?
iPeter,
27

Wiem, że to stara wiadomość, ale dodam moje dwa centy. Domyślnie używam poleceń, LIKE[cd]a nie tylko [c]. [d]Porównuje listów z symboli akcent. Działa to szczególnie dobrze w mojej aplikacji Warcraft, gdzie ludzie zapisują swoje imię „Vòódòó”, co sprawia, że ​​wyszukiwanie ich nazwiska w widoku tabeli jest prawie niemożliwe. [d]Taśmy ich symboli akcent podczas orzeczenia. Zatem predykat @"name LIKE[CD] %@", object.namegdzie object.name == @"voodoo"zwróci obiekt zawierający nazwę Vòódòó.

Z dokumentacji firmy Apple: jak [cd] oznacza „nieuwzględniające wielkości liter i znaków diakrytycznych, podobnie jak”). Aby uzyskać pełny opis składni łańcuchów i listę wszystkich dostępnych operatorów, zobacz Predicate Format String Składnia .

Obciążony Neuron
źródło
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;
}
Isaak Osipovich Dunayevsky
źródło
3

NSPredicate jest dostępny tylko w telefonie iPhone 3.0.

Nie zauważysz tego, dopóki nie spróbujesz uruchomić na urządzeniu.

Pręt
źródło
0

W Swift 3, gdy chcesz filtrować tablicę słowników za pomocą predykatu opartego na kluczach i wartościach słownika, możesz wybrać jeden z następujących wzorców.


# 1. Korzystanie z NSPredicate init(format:arguments:)inicjatora

Jeśli pochodzisz z Objective-C, init(format:arguments:) oferuje styl kodowania klucz-wartość do oceny predykatu.

Stosowanie:

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. Korzystanie z NSPredicate init(block:)inicjatora

Jako alternatywę, jeśli wolisz silnie wpisane API ponad stringly wpisywanych API można użyć init(block:)inicjator.

Stosowanie:

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"]]
Imanou Petit
źródło
-1

Patrząc na odniesienie NSPredicate , wygląda na to, że znak zastępczy należy otoczyć cudzysłowami. Na przykład, twój aktualny predykat czyta: (SPORT == Football)Chcesz, żeby był czytany (SPORT == 'Football'), więc twój ciąg formatu musi być @"(SPORT == '%@')".

Martin Gordon
źródło
Myślałem, że to też powiedział. Najwyraźniej cytaty nie są potrzebne. Nie jestem pewien, do czego przewodnik mówi, że cudzysłowy „powinny” być używane.
Corey Floyd