Utilizzo di NSPredicate per filtrare un NSArray in base alle chiavi NSDictionary


94

Ho una serie di dizionari.

Voglio filtrare l'array in base a una chiave.

Ho provato questo:

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

NSArray *filteredArray = [data filteredArrayUsingPredicate:predicate];

Non funziona, non ottengo risultati. Penso di fare qualcosa di sbagliato. So che questo è il metodo se "SPORT" fosse un ivar. Penso che probabilmente sia diverso se è una chiave.

Tuttavia non sono riuscito a trovare un esempio.

Grazie


Aggiornare

Ho aggiunto virgolette attorno alla stringa che sto cercando.

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

Ancora non funziona.


Aggiorna 2

Risolto. In realtà ho dovuto rimuovere le virgolette singole, il che sembra andare contro ciò che dice la guida.

Il mio vero problema è che avevo un array annidato e in realtà non stavo valutando i dizionari. Movimento della testa ossea.


Solo per menzionare che il predicato fa distinzione tra maiuscole e minuscole per impostazione predefinita (utilizzare [c] per non essere sensibile).
groumpf

Risposte:


151

Dovrebbe funzionare, purché la variabile di dati sia effettivamente un array contenente un dizionario con la chiave SPORT

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

Filtrato in questo caso contiene il dizionario.

(il% @ non deve essere citato, questo viene fatto quando NSPredicate crea l'oggetto.)


NSPredicate funziona su iPhone? Funziona benissimo sulla sim ma eseguendolo su iPhone dà un errore che non è stato possibile trovare la classe NSPredicate.
lostInTransit

NSPredicate è disponibile da iOS 3.0.
zekel

1
per chiarire ai nuovi programmatori come me, la riga di codice chiave è "NSArray * filtered = [data filteredArrayUsingPredicate: [NSPredicate predicateWithFormat: @" (BAR ==% @) ", @" foo "]];" dove 'data' è il nsarray di nsdictionaries che è già nel tuo codice. (grazie suraken)
tmr

E se i nomi delle chiavi sono dinamici?
iPeter

27

So che è una vecchia notizia, ma aggiungo i miei due centesimi. Per impostazione predefinita, uso i comandi LIKE[cd]anziché solo [c]. Il [d]confronto lettere con simboli di accento. Funziona particolarmente bene nella mia app Warcraft, dove le persone scrivono il loro nome "Vòódòó" rendendo quasi impossibile cercare il loro nome in una visualizzazione a tabella. Le [d]strisce i loro simboli di accento durante il predicato. Quindi un predicato di @"name LIKE[CD] %@", object.namedove object.name == @"voodoo"restituirà l'oggetto contenente il nome Vòódòó.

Dalla documentazione Apple: like [cd] significa “maiuscolo e diacritico-insensitive like.”) Per una descrizione completa della sintassi delle stringhe e un elenco di tutti gli operatori disponibili, vedere Predicate Format String Syntax .


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 è disponibile solo su iPhone 3.0.

Non te ne accorgerai finché non proverai a eseguire sul dispositivo.


0

Con Swift 3, quando desideri filtrare un array di dizionari con un predicato basato su chiavi e valori del dizionario, puoi scegliere uno dei seguenti modelli.


# 1. Utilizzando l' NSPredicate init(format:arguments:)inizializzatore

Se provieni da Objective-C, init(format:arguments:)offre uno stile di codifica valore-chiave per valutare il tuo predicato.

Utilizzo:

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. Utilizzando l' NSPredicate init(block:)inizializzatore

In alternativa, se preferisci le API fortemente tipizzate rispetto alle API tipizzate da stringhe , puoi usare l' init(block:)inizializzatore.

Utilizzo:

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

Guardando il riferimento NSPredicate , sembra che sia necessario racchiudere il carattere di sostituzione tra virgolette. Ad esempio, il tuo predicato corrente legge: (SPORT == Football)vuoi che legga (SPORT == 'Football'), quindi la stringa di formato deve essere @"(SPORT == '%@')".


Ho pensato che fosse anche quello che diceva. A quanto pare le virgolette non servono. Non sono sicuro di cosa stia dicendo la guida per cui le virgolette "dovrebbero" essere usate.
Corey Floyd
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.