基于 NSDictionary 键使用 NS谓词过滤 NSArray

我有一大堆字典。

我想根据一个键对数组进行过滤。

我试过了:

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


NSArray *filteredArray = [data filteredArrayUsingPredicate:predicate];

这样不行,我得不到任何结果。我觉得我做错了什么。我知道这是如果“ SPORT”是一个 ivar 的方法。我觉得如果是钥匙的话可能就不一样了。

然而,我还没有找到一个例子。

谢谢


更新

我在正在搜索的字符串周围添加了引号。

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

还是不行。


更新2

解决了,我不得不删除单引号,这似乎违背了指南所说的。

我真正的问题是,我有一个嵌套的数组,我并没有真正评估字典。

105805 次浏览

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 == '%@')".

It should work - as long as the data variable is actually an array containing a dictionary with the key SPORT

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

Filtered in this case contains the dictionary.

(the %@ does not have to be quoted, this is done when NSPredicate creates the object.)

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.

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

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