¿Hay una manera de iterar sobre un diccionario?


Conozco NSDictionaries como algo donde necesitas un key para obtener un value. Pero ¿cómo puedo iterar sobre todos keys y values en un NSDictionary, para saber qué claves hay, y qué valores hay? Sé que hay algo llamado for-in-loop en JavaScript. Hay algo similar en Objective-C?

Author: Alex Cio, 2009-08-16

3 answers

Sí, NSDictionary admite la enumeración rápida. Con Objective-C 2.0, puedes hacer esto:

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

El método alternativo (que debe usar si está apuntando a Mac OS X pre-10.5, pero aún puede usar en 10.5 y iPhone) es usar 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]);
 297
Author: Adam Rosenfield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-16 15:27:08

El enfoque de bloque evita ejecutar el algoritmo de búsqueda para cada clave :

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

Aunque NSDictionary se implementa como una hashtable (lo que significa que el costo de buscar un elemento es O(1)), las búsquedas todavía ralentizan su iteración por un factor constante.

Mis mediciones muestran que para un diccionario d de números ...

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

... resumiendo los números con el enfoque de bloque ...

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

... en lugar del enfoque de bucle ...

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

... es aproximadamente un 40% más rápido.

EDITAR : El nuevo SDK (6.1+) parece optimizar la iteración de bucle, por lo que el enfoque de bucle ahora es aproximadamente un 20% más rápido que el enfoque de bloque, al menos para el caso simple anterior.

 141
Author: Rok Strniša,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-12 20:38:35

Esta es la iteración usando el enfoque de bloque:

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

Con autocompletado es muy rápido de configurar, y no tiene que preocuparse por escribir sobre iteración.

 8
Author: Javier Calatrava Llavería,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-28 06:41:49