Uso de NSPredicate para filtrar un NSArray basado en claves NSDictionary

94

Tengo una variedad de diccionarios.

Quiero filtrar la matriz según una clave.

Probé esto:

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

NSArray *filteredArray = [data filteredArrayUsingPredicate:predicate];

Esto no funciona, no obtengo resultados. Creo que estoy haciendo algo mal. Sé que este es el método si "SPORT" fuera un ivar. Creo que probablemente sea diferente si se trata de una clave.

Sin embargo, no he podido encontrar un ejemplo.

Gracias


Actualizar

Agregué comillas alrededor de la cadena que estoy buscando.

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

Todavía no funciona.


Actualización 2

Resuelto. De hecho, tuve que eliminar las comillas simples, lo que parece ir en contra de lo que dice la guía.

Mi problema real es que tenía una matriz anidada y en realidad no estaba evaluando los diccionarios. Movimiento de cabeza de hueso.

Corey Floyd
fuente
Solo para mencionar que el predicado distingue entre mayúsculas y minúsculas por defecto (use [c] para volverse insensible).
groumpf

Respuestas:

151

Debería funcionar, siempre que la variable de datos sea en realidad una matriz que contenga un diccionario con la clave SPORT

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

Filtrado en este caso contiene el diccionario.

(el% @ no tiene que estar entre comillas, esto se hace cuando NSPredicate crea el objeto).

suraken
fuente
¿NSPredicate funciona en el iPhone? Funciona muy bien en la simulación, pero ejecutarlo en el iPhone da un error de que no se pudo encontrar la clase NSPredicate.
lostInTransit
NSPredicate está disponible desde iOS 3.0.
zekel
1
para aclarar a los nuevos codificadores como yo, la línea clave de código es 'NSArray * filter = [data filterArrayUsingPredicate: [NSPredicate predicateWithFormat: @ "(BAR ==% @)", @ "foo"]];' donde 'datos' es el nsarray de nsdictionaries que ya está en su código. (gracias suraken)
tmr
¿Qué pasa si los nombres de las claves son dinámicos?
iPeter
27

Sé que son noticias viejas, pero para agregar mis dos centavos. Por defecto, uso los comandos en LIKE[cd]lugar de solo [c]. El [d]compara las letras con símbolos de acento. Esto funciona especialmente bien en mi aplicación Warcraft, donde la gente deletrea su nombre "Vòódòó", lo que hace que sea casi imposible buscar su nombre en una vista de tabla. Las [d]tiras de sus símbolos de acento durante el predicado. Entonces, un predicado de @"name LIKE[CD] %@", object.namewhere object.name == @"voodoo"devolverá el objeto que contiene el nombre Vòódòó.

De la documentación de Apple: like [cd] significa “like insensible a mayúsculas y minúsculas y diacríticos.”) Para una descripción completa de la sintaxis de cadena y una lista de todos los operadores disponibles, vea Predicate Format String Syntax .

Neurona cargada
fuente
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
fuente
3

NSPredicate solo está disponible en iPhone 3.0.

No lo notará hasta que intente ejecutarlo en el dispositivo.

varilla
fuente
0

Con Swift 3, cuando desee filtrar una matriz de diccionarios con un predicado basado en claves y valores de diccionario, puede elegir uno de los siguientes patrones.


# 1. Usando NSPredicate init(format:arguments:)inicializador

Si viene de Objective-C, init(format:arguments:)ofrece un estilo de codificación de valor clave para evaluar su predicado.

Uso:

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. Usando NSPredicate init(block:)inicializador

Como alternativa, si prefiere las API fuertemente tipadas en lugar de las API escritas en cadena , puede usar el init(block:)inicializador.

Uso:

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
fuente
-1

Mirando la referencia de NSPredicate , parece que necesita rodear su carácter de sustitución con comillas. Por ejemplo, su predicado actual dice: (SPORT == Football)desea que se lea (SPORT == 'Football'), por lo que su cadena de formato debe ser @"(SPORT == '%@')".

Martin Gordon
fuente
Pensé que eso también decía. Aparentemente, las comillas no son necesarias. No estoy seguro de para qué dice exactamente la guía que las comillas "deberían" usarse.
Corey Floyd