Usando NSPredicate para filtrar um NSArray baseado em chaves NSDictionary

Eu tenho uma matriz de dictionarys.

Eu quero filtrar o array com base em uma chave.

Eu tentei isso:

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

Isso não funciona, não tenho resultados. Eu acho que estou fazendo algo errado. Eu sei que este é o método se “SPORT” fosse um ivar. Eu acho que é provavelmente diferente se é uma chave.

Eu não consegui encontrar um exemplo no entanto.

obrigado


Atualizar

Eu adicionei aspas ao redor da string que estou procurando.

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

Ele ainda não funciona.


Atualização 2

Resolvi-o. Eu realmente tive que remover as aspas simples, o que parece ir contra o que o guia diz.

Meu verdadeiro problema é que eu tinha uma matriz aninhada e eu não estava realmente avaliando os dictionarys. Movimento da cabeça do osso.

Ele deve funcionar – contanto que a variável de dados seja, na verdade, uma matriz contendo um dictionary com a chave SPORT.

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

Filtrado neste caso contém o dictionary.

(o% @ não precisa ser citado, isso é feito quando o NSPredicate cria o object.)

Eu sei que é notícia antiga, mas para adicionar meus dois centavos. Por padrão eu uso os comandos LIKE[cd] ao invés de apenas [c] . O [d] compara letras com símbolos de sotaque. Isso funciona especialmente bem no meu Warcraft App, onde as pessoas soletram o nome “Vòódòó”, tornando quase impossível procurar por seu nome em uma tableview. O [d] retira seus símbolos de acentuação durante o predicado. Portanto, um predicado de @"name LIKE[CD] %@", object.name onde object.name == @"voodoo" retornará o object contendo o nome Vòódòó.

Da documentação da Apple: como [cd] significa “insensível a maiúsculas e minúsculas”.) Para obter uma descrição completa da syntax da string e uma lista de todos os operadores disponíveis, consulte Sintaxe da sequência de formatação de predicado .

 #import  // 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; } 

NSPredicate está disponível apenas no iPhone 3.0.

Você não notará isso até tentar executar no dispositivo.

Com o Swift 3, quando você deseja filtrar uma matriz de dictionarys com um predicado baseado em chaves e valores de dictionary, você pode escolher um dos seguintes padrões.


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

Se você vem do Objective-C, o init(format:arguments:) oferece um estilo de codificação de valor-chave para avaliar seu 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 o init(block:) NSPredicate init(block:)

Como alternativa, se você preferir APIs fortemente tipadas sobre APIs tipadas , você pode usar o init(block:) .

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

Olhando para a referência NSPredicate , parece que você precisa cercar seu caractere de substituição com aspas. Por exemplo, o seu predicado atual diz: (SPORT == Football) Você quer que ele leia (SPORT == 'Football') , então sua string de formato precisa ser @"(SPORT == '%@')" .