Чи є спосіб перебрати словник?


200

Я знаю, NSDictionariesяк щось там, де вам потрібно key, щоб отримати value. Але як я можу повторювати над усіма keysі valuesв а 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 (@ "ключ =% @ значення =% @", ключ, myDict [ключ]);
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% .

EDIT : Новий 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.