使用 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。这是一个字典,其中一个字母(abcd)被键入一个数组。我们将找到与第一个元素为a 的数组对应的所有

我们的谓词是:

[NSPredicate predicateWithFormat:@"%@[SELF][0] == 'a'", d];

这里我们在源字典上使用索引运算符。 SELF,在评估此谓词时,将是 d 之一。所以%@[SELF] 会返回一个数组。然后我们获取该数组的第 0 个元素并将其与字符串 a 进行比较。如果匹配,则返回YES

然后我们抓取字典中的所有键并使用该谓词过滤它们。这意味着结果数组将仅包含对应数组的第一个元素为a 的键。

一旦我们有了匹配的键,我们就会从源字典中提取一个“子字典”来得到最终的精简字典。

在上面的测试中,matchingDictionary 有两个键(ad),它们都被键控到包含 (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 搜索/过滤自定义类数组

使用 NSPredicate 过滤对象中的数组

使用 NSPredicate 过滤 NSDictionary 中的值并返回键数组

使用 NSPredicate 根据数组属性过滤 CoreData 项列表

我想要 swift3.0 的 NSPredicate 的数组过滤器数组