web-dev-qa-db-fra.com

Y a-t-il un moyen de parcourir un dictionnaire?

Je sais que NSDictionaries est un domaine dans lequel vous avez besoin d'un key pour pouvoir obtenir un value. Mais comment puis-je parcourir tous les keys et values dans un NSDictionary afin de savoir quelles sont les clés et quelles sont les valeurs? Je sais qu'il y a quelque chose appelé un for-in-loop dans JavaScript. Y a-t-il quelque chose de similaire dans Objective-C?

195
HelloMoon

Oui, NSDictionary prend en charge l'énumération rapide. Avec Objective-C 2.0, vous pouvez faire ceci:

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

La méthode alternative (que vous devez utiliser si vous ciblez Mac OS X d’avant la version 10.5, mais que vous pouvez toujours utiliser sur 10.5 et sur un iPhone) consiste à utiliser un 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

L'approche par blocs évite l'exécution de l'algorithme de recherche pour chaque clé:

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

Même si NSDictionary est implémenté en tant que hashtable (ce qui signifie que le coût de la recherche d'un élément est O(1) ), les recherches ralentissent toujours votre itération de un facteur constant.

Mes mesures montrent que pour un dictionnaire d de nombres ...

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

... résumant les nombres avec l'approche par blocs ...

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

... plutôt que l'approche en boucle ...

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

... est environ 40% plus rapide .

[~ # ~] edit [~ # ~] : le nouveau SDK (6.1+) apparaît pour optimiser l'itération de la boucle, donc l'approche en boucle est maintenant environ 20% plus rapide que l'approche en bloc , au moins pour le cas simple ci-dessus.

149
Rok Strniša

Ceci est une approche itérative utilisant des blocs:

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

Avec l'auto-complétion est très rapide à définir, et vous n'avez pas à vous soucier d'écrire l'enveloppe d'itération.