[objective-c] Using NSPredicate to filter an NSArray based on NSDictionary keys

I have an array of dictionaries.

I want to filter the array based on a key.

I tried this:

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

NSArray *filteredArray = [data filteredArrayUsingPredicate:predicate];

This doesn't work, I get no results. I think I'm doing something wrong. I know this is the method if "SPORT" was an ivar. I think it is probably different if it is a key.

I haven't been able to find an example however.

Thanks


Update

I added quotes around the string I am searching for.

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

It still does not work.


Update 2

Solved it. I actually had to remove the single quotes, which seems to go against what the guide says.

My real problem is I had a nested array and I wasn't actually evaluating the dictionaries. Bone head move.

This question is related to objective-c cocoa nsarray nsdictionary nspredicate

The answer is


With Swift 3, when you want to filter an array of dictionaries with a predicate based on dictionary keys and values, you may choose one of the following patterns.


#1. Using NSPredicate init(format:arguments:) initializer

If you come from Objective-C, init(format:arguments:) offers a key-value coding style to evaluate your predicate.

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. Using NSPredicate init(block:) initializer

As an alternative if you prefer strongly typed APIs over stringly typed APIs, you can use init(block:) initializer.

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

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

Looking at the NSPredicate reference, it looks like you need to surround your substitution character with quotes. For example, your current predicate reads: (SPORT == Football) You want it to read (SPORT == 'Football'), so your format string needs to be @"(SPORT == '%@')".


NSPredicate is only available in iPhone 3.0.

You won't notice that until try to run on device.


I know it's old news but to add my two cents. By default I use the commands LIKE[cd] rather than just [c]. The [d] compares letters with accent symbols. This works especially well in my Warcraft App where people spell their name "Vòódòó" making it nearly impossible to search for their name in a tableview. The [d] strips their accent symbols during the predicate. So a predicate of @"name LIKE[CD] %@", object.name where object.name == @"voodoo" will return the object containing the name Vòódòó.

From the Apple documentation: like[cd] means “case- and diacritic-insensitive like.”) For a complete description of the string syntax and a list of all the operators available, see Predicate Format String Syntax.


Examples related to objective-c

Adding a UISegmentedControl to UITableView Keep placeholder text in UITextField on input in IOS Accessing AppDelegate from framework? Warp \ bend effect on a UIView? Use NSInteger as array index Detect if the device is iPhone X Linker Command failed with exit code 1 (use -v to see invocation), Xcode 8, Swift 3 ITSAppUsesNonExemptEncryption export compliance while internal testing? How to enable back/left swipe gesture in UINavigationController after setting leftBarButtonItem? Change status bar text color to light in iOS 9 with Objective-C

Examples related to cocoa

How to update a single pod without touching other dependencies How to initialise a string from NSData in Swift Input from the keyboard in command line application Get current NSDate in timestamp format Xcode build failure "Undefined symbols for architecture x86_64" Cocoa Autolayout: content hugging vs content compression resistance priority setValue:forUndefinedKey: this class is not key value coding-compliant for the key iOS - Build fails with CocoaPods cannot find header files Get Current date & time with [NSDate date] Remove all whitespaces from NSString

Examples related to nsarray

Initialize Array of Objects using NSArray How to convert NSNumber to NSString NSDictionary to NSArray? Convert NSArray to NSString in Objective-C How do I convert NSMutableArray to NSArray? NSArray + remove item from array How do I iterate over an NSArray? Using NSPredicate to filter an NSArray based on NSDictionary keys How can I reverse a NSArray in Objective-C? filtering NSArray into a new NSArray in Objective-C

Examples related to nsdictionary

How to append elements into a dictionary in Swift? Converting NSString to NSDictionary / JSON convert NSDictionary to NSString How do I deserialize a JSON string into an NSDictionary? (For iOS 5+) How to use NSJSONSerialization adding multiple entries to a HashMap at once in one statement How can I convert NSDictionary to NSData and vice versa? How to add to an NSDictionary NSDictionary to NSArray? NSDictionary - Need to check whether dictionary contains key-value pair or not

Examples related to nspredicate

Using NSPredicate to filter an NSArray based on NSDictionary keys