Utilisation de NSPredicate pour filtrer un NSArray basé sur des clés NSDictionary

94

J'ai une panoplie de dictionnaires.

Je souhaite filtrer le tableau en fonction d'une clé.

J'ai essayé ceci:

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

NSArray *filteredArray = [data filteredArrayUsingPredicate:predicate];

Cela ne fonctionne pas, je n'obtiens aucun résultat. Je pense que je fais quelque chose de mal. Je sais que c'est la méthode si "SPORT" était un ivar. Je pense que c'est probablement différent s'il s'agit d'une clé.

Je n'ai cependant pas pu trouver d'exemple.

Merci


Mettre à jour

J'ai ajouté des guillemets autour de la chaîne que je recherche.

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

Cela ne fonctionne toujours pas.


Mise à jour 2

Résolu. En fait, j'ai dû supprimer les guillemets simples, ce qui semble aller à l'encontre de ce que dit le guide.

Mon vrai problème est que j'avais un tableau imbriqué et que je n'évaluais pas réellement les dictionnaires. Mouvement de la tête osseuse.

Corey Floyd
la source
Juste pour mentionner que le prédicat est sensible à la casse par défaut (utilisez [c] pour être insensible).
groumpf

Réponses:

151

Cela devrait fonctionner - tant que la variable de données est en fait un tableau contenant un dictionnaire avec la clé SPORT

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

Filtré dans ce cas contient le dictionnaire.

(le% @ n'a pas besoin d'être entre guillemets, cela est fait lorsque NSPredicate crée l'objet.)

suraken
la source
NSPredicate fonctionne-t-il sur l'iPhone? Cela fonctionne très bien sur la carte SIM, mais son exécution sur l'iPhone donne une erreur indiquant que la classe NSPredicate n'a pas pu être trouvée.
lostInTransit
NSPredicate est disponible depuis iOS 3.0.
zekel du
1
pour clarifier pour les nouveaux codeurs comme moi, la ligne de code clé est 'NSArray * filtered = [data filteredArrayUsingPredicate: [NSPredicate predicateWithFormat: @ "(BAR ==% @)", @ "foo"]];' où 'data' est le nsarray de nsdictionaries qui est déjà dans votre code. (merci suraken)
tmr
Et si les noms de clé sont dynamiques?
iPeter
27

Je sais que ce sont de vieilles nouvelles mais pour ajouter mes deux cents. Par défaut, j'utilise les commandes LIKE[cd]plutôt que juste [c]. Le [d]compare les lettres avec des symboles d'accent. Cela fonctionne particulièrement bien dans mon application Warcraft où les gens épellent leur nom "Vòódòó", ce qui rend presque impossible la recherche de leur nom dans une vue de table. Les [d]bandes leurs symboles d'accent pendant le prédicat. Donc, un prédicat d' @"name LIKE[CD] %@", object.nameobject.name == @"voodoo"retournera l'objet contenant le nom Vòódòó.

Extrait de la documentation Apple: comme [cd] signifie «insensible à la casse et au diacritique comme».) Pour une description complète de la syntaxe de chaîne et une liste de tous les opérateurs disponibles, voir Syntaxe de chaîne de format de prédicat .

ChargéNeuron
la source
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
la source
3

NSPredicate n'est disponible que sur l'iPhone 3.0.

Vous ne le remarquerez pas avant d'essayer de l'exécuter sur l'appareil.

Barre
la source
0

Avec Swift 3, lorsque vous souhaitez filtrer un tableau de dictionnaires avec un prédicat basé sur des clés et des valeurs de dictionnaire, vous pouvez choisir l'un des modèles suivants.


#1. Utilisation de l' NSPredicate init(format:arguments:)initialiseur

Si vous venez d'Objective-C, init(format:arguments:)propose un style de codage clé-valeur pour évaluer votre prédicat.

Usage:

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. Utilisation de l' NSPredicate init(block:)initialiseur

Comme alternative si vous préférez les API fortement typées aux API de type string , vous pouvez utiliser l' init(block:)initialiseur.

Usage:

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
la source
-1

En regardant la référence NSPredicate , il semble que vous deviez entourer votre caractère de substitution de guillemets. Par exemple, votre prédicat actuel lit: (SPORT == Football)Vous voulez qu'il soit lu (SPORT == 'Football'), donc votre chaîne de format doit l'être @"(SPORT == '%@')".

Martin Gordon
la source
Je pensais que c'était aussi ce qu'il disait. Apparemment, les citations ne sont pas nécessaires. Je ne sais pas exactement à quoi le guide dit que les citations "devraient" être utilisées.
Corey Floyd