Si todos los diccionarios tienen el mismo conjunto de llaves, entonces se podría hacer algo bastante simple:
NSArray *keys = ...; //the list of keys that all of the dictionaries contain
NSMutableArray *subpredicates = [NSMutableArray array];
for (NSString *key in keys) {
NSPredicate *subpredicate = [NSPredicate predicateWithFormat:@"%K contains[cd] %@", key, searchText];
[subpredicates addObject:subpredicate];
}
NSPredicate *filter = [NSCompoundPredicate orPredicateWithSubpredicates:subpredicates];
entonces usted puede utilizar para filtrar su filter
NSArray
(usando -filteredArrayUsingPredicate
).
Si, por el contrario, tiene una serie de diccionarios arbitrarias que todos tienen diferentes claves, que había necesidad de algo un poco más perversa:
NSPredicate *filter = [NSPredicate predicateWithFormat:@"SUBQUERY(FUNCTION(SELF, 'allKeys'), $k, SELF[$k] contains[cd] %@)[email protected] > 0", searchText];
Un poco acerca de lo que está haciendo esto:
FUNCTION(SELF, 'allKeys')
- esto se ejecutará en -allKeys
SELF
(un NSDictionary
) y devolver una NSArray
de todas las teclas en el diccionario
SUBQUERY(allKeys, $k, SELF[$k] contains[cd] %@)
- Esto iterará sobre cada elemento en allKeys
, con cada artículo sucesivo colocado en la variable $k
. Para cada artículo, se ejecutará SELF[$k] contains %@
. Esto básicamente terminará haciendo: [theDictionary objectForKey:$k] contains[cd] %@
. Si esto devuelve YES
, el elemento $k
se agregará en una nueva matriz.
SUBQUERY(...)[email protected] > 0
- después de encontrar todas las claves que corresponden a los valores que contienen su texto de búsqueda, verificamos y vemos si hubo alguna. Si hubiera (es decir, el tamaño de la matriz es mayor que 0), entonces el diccionario general será parte de la matriz filtrada final.
Recomiendo ir con la primera aproximación, si es posible. SUBQUERY
y FUNCTION
son un poco arcanas, y la primera es mucho más fácil de entender.
Y aquí hay otra forma, que casi tenía en su pregunta. En lugar de hacer ANY SELF.allValues contains[cd] %@
, puede hacer ANY FUNCTION(SELF, 'allValues') contains[cd] %@
.Esto es equivalente a mi locura SUBQUERY
, pero mucho más simple. Felicitaciones a ti por pensar en usar ANY
(normalmente me olvido de que existe).
EDITAR
La razón SELF.allValues
no funciona, es que esto se interpreta como una ruta de acceso clave, y -[NSDictionary valueForKey:]
is supposed to be the same as-[NSDictionary objectForKey:]
. El problema aquí es que si prefijas la clave con @
, luego lo reenvía a [super valueForKey:]
, que hará haciendo lo que estás esperando. Por lo que podría realmente hacer:
ANY [email protected] contains[cd] %@
O simplemente:
ANY @allValues contains[cd] %@
, siendo este punto (y es el mejor y más simple enfoque).
Hola, gracias por la respuesta en profundidad :-) El conjunto de encabezados no será necesariamente el mismo entre los diccionarios, por lo que no podría usar el primer método que mencionaste. Los otros se veían bien, pero he tenido un intento con el último, por lo que puedo decir, recibo una excepción si busco algo que filtre. es decir, si busco una sola letra que esté presente en todos los diccionarios, funciona, cualquier otra cosa y falla, obtengo: *** Aplicación de terminación debido a la excepción no detectada 'NSInvalidArgumentException', razón: 'No se puede usar in/contains operador con la colección 0 (no una colección) ' – mcknut
@mcknut ¿Puede poner más información en la pregunta sobre los datos en los diccionarios, y también un ejemplo específico de cómo arroja esa excepción? –
la excepción se da si busco "!" que sería bastante raro en los diccionarios. De hecho, estoy pensando que "lo estoy haciendo mal" y que debería pasar a usar Core Data. En ese escenario, almacenaría las claves y valores en su propia entidad con una referencia de regreso a la entidad principal y luego buscaría las entidades de clave y valor para buscar coincidencias, creo que sería lo mejor. – mcknut