2009-08-16 12 views
178

NSDictionaries como algo donde necesita un key para obtener un value. Pero ¿cómo puedo iterar sobre 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?¿Hay alguna manera de iterar sobre un diccionario?

Respuesta

287

Sí, NSDictionary admite la enumeración rápida. Con Objective-C 2.0, usted puede 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 usted tiene que utilizar si se orienta a Mac OS X pre-10.5, pero todavía se puede utilizar en el 10,5 y el iPhone) es utilizar 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]); 
+4

El enfoque de bloque es más rápido. Ver http://stackoverflow.com/a/12454766/974531. –

+2

Sintaxis moderna ObjC: NSLog (@ "clave =% @ valor =% @", clave, myDict [clave]); – geowar

+0

@Darthenius debido a las optimizaciones recientes, la enumeración rápida es de nuevo más rápida que la basada en bloques, al menos en ciertos casos. Pero si el problema que está resolviendo le permite usar la opción concurrente, el enfoque basado en bloques puede ser más rápido. –

137

el enfoque de bloques de evita ejecutar el algoritmo de búsqueda para cada llave :

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

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

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

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 bloques ...

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

... en lugar de el enfoque de bucle ...

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

... es ab fuera 40% más rápido.

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

+0

¿Qué hay de iOS 10/11, cuál es más rápido? – Supertecnoboff

+0

elegante, ¡me encanta! – YvesLeBorg

5

Ésta es la iteración usando el enfoque de bloques:

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 la terminación automática es muy rápido para establecer, y usted no tiene que preocuparse de escribir sobre iteración.

+0

Gracias .. Buena solución si necesita mutar el 'NSMutableDictionary' en el proceso – jose920405

Cuestiones relacionadas