Есть ли способ перебора словаря?

200

Я знаю, NSDictionariesкак то, что вам нужно key, чтобы получить value. Но как я могу перебрать все keysи valuesв a NSDictionary, чтобы я знал, какие есть ключи и какие есть значения? Я знаю , что есть нечто , называемое для-в-петли в JavaScript. Есть ли что-то подобное в Objective-C?

Алекс Чио
источник
Спасибо за этот пост. Если итерация в Swiftсинтаксисе, обратитесь к этому сообщению: stackoverflow.com/a/24111700/419348
AechoLiu

Ответы:

323

Да, 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 из-за недавних оптимизаций, быстрое перечисление снова быстрее, чем на основе блоков, по крайней мере, в некоторых случаях. Но если проблема, которую вы решаете, позволяет вам использовать параллельную опцию, подход на основе блоков может быть быстрее.
Зев Айзенберг
@ZevEisenberg Смотрите в конце моего поста.
Рок Стрниша
К сожалению, я нажал на вашу ссылку выше, чтобы открыть в новой вкладке, и даже не заметил, кто написал или что это было на этой же странице. Если вы все еще можете отредактировать приведенный выше комментарий, возможно, вы захотите, чтобы ленивые читатели не поняли неверное представление.
Зев Айзенберг
153

Блочный подход позволяет избежать запуска алгоритма поиска для каждого ключа :

[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
элегантный, люблю это!
ИвЛеборг
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
изменить