web-dev-qa-db-ja.com

辞書を反復処理する方法はありますか?

NSDictionariesを取得するには、keyが必要な場所としてvalueを知っています。しかし、keys内のすべてのvaluesおよびNSDictionaryを反復処理して、どのキーがあり、どの値があるのか​​を知るにはどうすればよいですか? JavaScriptにはfor-in-loopと呼ばれるものがあります。 Objective-Cに類似したものはありますか?

195
HelloMoon

はい、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]);
313
Adam Rosenfield

ブロックアプローチは、すべてのキーのルックアップアルゴリズムの実行を回避します:

[dict enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL* stop) {
  NSLog(@"%@ => %@", key, value);
}];

NSDictionaryhashtable として実装されている場合でも(つまり、要素を検索するコストが O(1) であることを意味します)、ルックアップは繰り返しを遅くしますbya constant factor

私の測定では、辞書の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%高速です

EDIT:新しいSDK(6.1+)はループの繰り返しを最適化するように見えるため、ループアプローチは少なくとも上記の単純なケースでは、ブロックアプローチよりも約20%高速です。

149
Rok Strniša

これは、ブロックアプローチを使用した反復です。

    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.
    }];

オートコンプリートを使用すると、設定が非常に高速であり、反復エンベロープを記述することを心配する必要はありません。