有没有一种方法可以遍历字典?

221

我知道 NSDictionaries 是需要一个 key 才能获取对应的 value 的。但是,我该如何遍历所有 keysvalues 并了解有哪些键和值? 我知道在 JavaScript 中有一种叫做 for-in-loop 的东西。 在 Objective-C 中有类似的东西吗?


感谢这篇文章。如果使用Swift语法进行迭代,请参考此帖子:https://dev59.com/zmAf5IYBdhLWcg3w9Wiu#24111700 - AechoLiu
您可以探索一下我谦虚的字典迭代技巧研究:https://stackoverflow.com/questions/71626497/obj-c-extracting-all-values-from-nsdictionary-without-copying - BorisV
3个回答

360

是的,NSDictionary 支持快速枚举。使用 Objective-C 2.0,你可以这样做:

// To print out all key-value pairs in the NSDictionary myDict
for(id key in myDict)
    NSLog(@"key=%@ value=%@", key, [myDict objectForKey:key]);

如果你的目标是针对Mac OS X 10.5以前的版本,那么你需要使用以下替代方法(但是在10.5及其以上版本和iPhone上也可以使用),即使用NSEnumerator

NSEnumerator *enumerator = [myDict keyEnumerator];
id key;
// extra parens to suppress warning about using = instead of ==
while((key = [enumerator nextObject]))
    NSLog(@"key=%@ value=%@", key, [myDict objectForKey:key]);

2
ObjC现代语法:NSLog(@"key=%@ value=%@", key, myDict[key]); - geowar
@Darthenius,由于最近的优化,快速枚举再次比基于块的方法更快,至少在某些情况下是如此。但是,如果您解决的问题允许您使用并发选项,则基于块的方法可能更快。 - Zev Eisenberg
@ZevEisenberg 请看我帖子的结尾。 - Rok Strniša
哎呀,我点击了你的链接,在新标签页中打开了它,甚至没有注意到是谁写的或者它在同一页上。如果你仍然可以编辑上面的评论,你可能需要这样做,以便懒惰的读者不会产生错误的想法。 - Zev Eisenberg

164
块状方法避免为每个键运行查找算法:
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL* stop) {
  NSLog(@"%@ => %@", key, value);
}];

尽管NSDictionary被实现为哈希表(这意味着查找元素的成本为O(1)),但查找仍会通过常数因子减缓迭代速度。

我的测量结果显示,对于一个数字字典d...

NSMutableDictionary* dict = [NSMutableDictionary dictionary];
for (int i = 0; i < 5000000; ++i) {
  NSNumber* value = @(i);
  dict[value.stringValue] = value;
}

使用块级方法对数字进行求和...

__block int sum = 0;
[dict enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSNumber* value, BOOL* stop) {
  sum += value.intValue;
}];

相较于循环方法,更推荐使用其他方法...

int sum = 0;
for (NSString* key in dict)
  sum += [dict[key] intValue];

... 快了约40%

编辑:新的SDK(6.1+)似乎优化了循环迭代,因此对于上述简单情况,循环方法现在比块方法快了约20%


在iOS 10/11中,哪一个更快? - Supertecnoboff
优雅,喜欢它! - YvesLeBorg

10

这是使用块方法的迭代:

    NSDictionary *dict = @{@"key1":@1, @"key2":@2, @"key3":@3};

    [dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        NSLog(@"%@->%@",key,obj);
        // Set stop to YES when you wanted to break the iteration.
    }];
使用自动完成非常快速方便,而且您不必担心编写循环包装。

使用自动完成非常快速方便,而且您不必担心编写循环包装。


谢谢。如果您需要在过程中更改NSMutableDictionary,这是一个很好的解决方案。 - jose920405

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接