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.


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).


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 .


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 jest dostępny tylko w telefonie iPhone 3.0.

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


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"]]

-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 == '%@')".


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.