Usando NSPredicate para filtrar um NSArray com base em chaves NSDictionary

94

Eu tenho uma variedade de dicionários.

Quero filtrar a matriz 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 obtenho resultados. Acho que estou fazendo algo errado. Eu sei que este é o método se "SPORT" fosse um ivar. Acho que provavelmente é diferente se for uma chave.

Não fui capaz de encontrar um exemplo, entretanto.

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. Na verdade, tive que remover as aspas simples, o que parece ir contra o que o guia diz.

Meu verdadeiro problema é que eu tinha um array aninhado e não estava realmente avaliando os dicionários. Movimento de cabeça de osso.

Corey Floyd
fonte
Apenas para mencionar que o predicado diferencia maiúsculas de minúsculas por padrão (use [c] para não diferenciar).
groumpf
possível duplicata da matriz de classificação
QED

Respostas:

151

Deve funcionar - desde que a variável de dados seja na verdade uma matriz contendo um dicionário 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 dicionário.

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

Suraken
fonte
O NSPredicate funciona no iPhone? Funciona muito bem no sim, mas executá-lo no iPhone dá um erro de que a classe NSPredicate não foi encontrada.
perdido no trânsito de
NSPredicate está disponível desde iOS 3.0.
zekel
1
para esclarecer para novos codificadores como eu, a linha principal do código é 'NSArray * filter = [data filterArrayUsingPredicate: [NSPredicate predicateWithFormat: @ "(BAR ==% @)", @ "foo"]];' onde 'dados' é o nsarray de nsdictionaries que já está em seu código. (obrigado suraken)
tmr
E se os nomes das chaves forem dinâmicos?
iPeter
27

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

Da documentação da Apple: como [cd] significa “não sensível a maiúsculas e minúsculas, como.”) Para uma descrição completa da sintaxe da string e uma lista de todos os operadores disponíveis, consulte Sintaxe da string de formato de predicado .

ChargedNeuron
fonte
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
fonte
3

NSPredicate está disponível apenas no iPhone 3.0.

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

Cajado
fonte
0

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


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

Se você vem de Objective-C, 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 NSPredicate init(block:)inicializador

Como alternativa, se você preferir APIs fortemente tipadas em vez de APIs com strings , você pode usar o 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
fonte
-1

Olhando a referência NSPredicate , parece que você precisa colocar seu caractere de substituição entre aspas. Por exemplo, seu predicado atual lê: (SPORT == Football)Você deseja que seja lido (SPORT == 'Football'), então sua string de formato precisa ser @"(SPORT == '%@')".

Martin Gordon
fonte
Eu pensei que era o que dizia também. Aparentemente, as aspas não são necessárias. Não sei exatamente para que o guia está dizendo que as aspas "deveriam" ser usadas.
Corey Floyd