使用 NSPredicate 过滤数组的 NSDictionary
Posted
技术标签:
【中文标题】使用 NSPredicate 过滤数组的 NSDictionary【英文标题】:Filter an NSDictionary of Arrays using NSPredicate 【发布时间】:2011-01-28 15:19:04 【问题描述】:我有一个 plist,我已将其定义为包含许多数组的 Dictionary。我想从该字典中提取所有具有与给定字符串匹配的第一个“项目 0”(默认命名约定)的数组。
我尝试了类似于过滤 NSArray 的方法,但我收到了一个正则表达式错误,并且控制台会显示字典中第一个数组的内容。
另外,我是否需要将我的 NSDictionary 实例化为 NSMutableDictionary,因为我将对其执行过滤过程?将从 plist 读入的 NSDictionary 复制到一个必须的,然后对其进行处理是不是更好的形式?
【问题讨论】:
【参考方案1】:这是可能的,但以迂回的方式。我建议您考虑使用不同的方法。
话虽如此,这就是你的做法:
NSDictionary *d = [NSDictionary dictionaryWithObjectsAndKeys:
[NSArray arrayWithObjects:@"a", @"b", @"c", nil], @"a",
[NSArray arrayWithObjects:@"b", @"c", @"a", nil], @"b",
[NSArray arrayWithObjects:@"c", @"a", @"b", nil], @"c",
[NSArray arrayWithObjects:@"a", @"b", @"c", nil], @"d",
nil];
NSPredicate *p = [NSPredicate predicateWithFormat:@"%@[SELF][0] == 'a'", d];
NSLog(@"%@", p);
NSArray *keys = [d allKeys];
NSArray *filteredKeys = [keys filteredArrayUsingPredicate:p];
NSLog(@"%@", filteredKeys);
NSDictionary *matchingDictionary = [d dictionaryWithValuesForKeys:filteredKeys];
NSLog(@"%@", matchingDictionary);
这是怎么回事:
我们有我们的源字典,d
。这是一个字典,其中一个字母(a
、b
、c
或 d
)被键入一个数组。我们将找到与第一个元素为a
的数组对应的所有键。
我们的谓词是:
[NSPredicate predicateWithFormat:@"%@[SELF][0] == 'a'", d];
这里我们在源字典上使用索引运算符。 SELF
,在评估此谓词时,将是 d
的 键 之一。所以%@[SELF]
会返回一个数组。然后我们获取该数组的第 0 个元素并将其与字符串 a
进行比较。如果匹配,则返回YES
。
然后我们抓取字典中的所有键并使用该谓词过滤它们。这意味着结果数组将仅包含对应数组的第一个元素为a
的键。
一旦我们有了匹配的键,我们就会从源字典中提取一个“子字典”来得到最终的精简字典。
在上面的测试中,matchingDictionary
有两个键(a
和 d
),它们都被键控到包含 (a, b, c)
的数组。
如果您想要一个包含匹配数组的NSArray
,则可以改用-[NSDictionary objectsForKeys:notFoundMarker:]
。
但是,这是一个尴尬的解决方案,我仍然认为您应该重新组织数据。
【讨论】:
我最终重组了我的 plist 数据文件。这样我就可以更好地使用 NSPredicate。【参考方案2】:我很确定你不能在这里使用 NSPredicate (尽管如果你想在 NSDictionary 中的数组上使用 NSPredicate你可以)。但是,有一个完全可以接受的替代方案,如下例所示:
NSMutableArray* filteredArrays = [[NSMutableArray alloc] init];
for (NSString* currentKey in myDictionaryOfArrays)
NSArray* currentArray = [myDictionaryOfArrays objectForKey:currentKey];
NSString* objectAtFirstIndex = [currentArray objectAtIndex:0];
if ([objectAtFirstIndex isEqualTo:mySearchString]);
[filteredArrays addObject:currentArray];
顺便说一句,应该使用快速枚举(“for each”)语句,因为您可以从中获得性能提升。
剩下的是一个可变数组,它与您的搜索条件相匹配。如果您想更整洁一些(例如,如果此代码形成一个方法),您可以将其转换为非可变数组(当然,除非您想继续进行更改)。
NSArray* filteredResults = [NSArray arrayWithArray:filteredArrays];
【讨论】:
大部分是正确的,除了在for...in
循环中使用字典时,您最终会遍历 键,而不是值。
我喜欢这个解决方案,但看不到这是如何“迭代键”。 NSString* objectAtFirstIndex = [currentArray objectAtIndex:0]; if ([objectAtFirstIndex isEqualTo:mySearchString]); objectAtFirstIndex 被分配了当前数组的值而不是键。对吗?
对不起,伙计们,我忘记了 itarator 翻过钥匙了。我已经更新了示例代码。以上是关于使用 NSPredicate 过滤数组的 NSDictionary的主要内容,如果未能解决你的问题,请参考以下文章
使用 NSPredicate 过滤数组的 NSDictionary
使用 NSPredicate 过滤 NSDictionary 中的值并返回键数组