使用 NSPredicate 根据 NSDictionary 键过滤 NSArray

Posted

技术标签:

【中文标题】使用 NSPredicate 根据 NSDictionary 键过滤 NSArray【英文标题】:Using NSPredicate to filter an NSArray based on NSDictionary keys 【发布时间】:2010-10-31 19:29:40 【问题描述】:

我有一个字典数组。

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

我试过了:

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

NSArray *filteredArray = [data filteredArrayUsingPredicate:predicate];

这不起作用,我没有得到任何结果。我想我做错了什么。如果“SPORT”是 ivar,我知道这就是方法。如果是钥匙的话,我想可能会有所不同。

但是我找不到一个例子。

谢谢


更新

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

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

还是不行。


更新 2

解决了。我实际上不得不删除单引号,这似乎与指南所说的背道而驰。

我真正的问题是我有一个嵌套数组,我实际上并没有评估字典。骨头移动。

【问题讨论】:

只是提到谓词默认区分大小写(使用[c]变得不敏感)。 ios sorting array of dictionaries by key of inner dictionary的可能重复 【参考方案1】:

它应该可以工作 - 只要数据变量实际上是一个包含带有键 SPORT 的字典的数组

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

Filtered 在这种情况下包含字典。

(%@ 不必被引用,这是在 NSPredicate 创建对象时完成的。)

【讨论】:

NSPredicate 能否在 iPhone 上运行?它在 sim 上运行良好,但在 iPhone 上运行它会给出一个错误,即找不到 NSPredicate 类。 NSPredicate 从 iOS 3.0 开始可用。 为像我这样的新程序员澄清一下,代码的关键行是 'NSArray *filtered = [data filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"(BAR == %@)", @"foo" ]];'其中“数据”是您的代码中已经存在的 nsdictionaries 的 nsarray。 (谢谢你) 如果键名是动态的怎么办?【参考方案2】:

我知道这是旧消息,但要加上我的两分钱。默认情况下,我使用命令LIKE[cd] 而不仅仅是[c][d] 将字母与重音符号进行比较。这在我的魔兽应用程序中特别有效,人们拼写他们的名字“Vòódòó”,几乎不可能在表格视图中搜索他们的名字。 [d] 在谓词中去掉了它们的重音符号。所以 @"name LIKE[CD] %@", object.name 的谓词,其中 object.name == @"voodoo" 将返回包含名称 Vòódòó 的对象。

来自 Apple 文档: like[cd] 表示“不区分大小写和变音符号的like”。)有关字符串语法的完整描述和所有可用运算符的列表,请参阅Predicate Format String Syntax

【讨论】:

【参考方案3】:
#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;

【讨论】:

【参考方案4】:

NSPredicate 仅适用于 iPhone 3.0。

在尝试在设备上运行之前,您不会注意到这一点。

【讨论】:

【参考方案5】:

在 Swift 3 中,当您想要使用基于字典键和值的谓词过滤字典数组时,您可以选择以下模式之一。


#1。使用NSPredicateinit(format:arguments:)初始化器

如果您来自 Objective-C,init(format:arguments:) 提供了一种键值编码风格来评估您的谓词。

用法:

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。使用NSPredicateinit(block:)初始化器

如果您更喜欢强类型 API 而不是字符串类型 API,则可以使用init(block:) 初始化程序。

用法:

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

【讨论】:

【参考方案6】:

查看NSPredicate reference,您似乎需要用引号将替换字符括起来。例如,您当前的谓词为:(SPORT == Football) 您希望它为(SPORT == 'Football'),因此您的格式字符串需要为@"(SPORT == '%@')"

【讨论】:

我也认为它是这么说的。显然不需要引号。我不确定指南所说的“应该”用于什么。

以上是关于使用 NSPredicate 根据 NSDictionary 键过滤 NSArray的主要内容,如果未能解决你的问题,请参考以下文章

如何根据多对关系集是不是包含特定值使用 NSPredicate 进行过滤

NSPredicate 根据本地化字符串条目过滤数组

NSPredicate 根据嵌套结构中的属性过滤自定义对象

iOS核心数据如何使用NSPredicate根据一对多的子属性查找父对象?

NSPredicate 根据谓语动词 进行 模糊查询

NSPredicate 的使用