2009-08-16 12 views
178

Znam NSDictionaries jako coś, czego potrzebujesz key, aby uzyskać value. Ale jak mogę iterować po wszystkich keys i values w NSDictionary, tak że wiem, jakie są klucze i jakie są wartości? Wiem, że jest coś o nazwie dla pętli w pętli w JavaScript. Czy jest coś podobnego w Objective-C?Czy istnieje sposób do iteracji w słowniku?

Odpowiedz

287

Tak, NSDictionary obsługuje szybkie wyliczanie. Z Objective-C 2.0, można to zrobić:

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

Sposób alternatywny (które trzeba użyć, jeśli jesteś kierowania Mac OS X 10.5 wstępnie, ale nadal można używać na 10,5 i iPhone) jest aby użyć 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

Podejście blokowe jest szybsze. Zobacz http://stackoverflow.com/a/12454766/974531. –

+2

Nowoczesna składnia ObjC: NSLog (@ "key =% @ value =% @", key, myDict [key]); – geowar

+0

@Darthenius ze względu na ostatnie optymalizacje, szybkie wyliczanie jest ponownie szybsze niż oparte na blokach, przynajmniej w niektórych przypadkach. Ale jeśli problem, który rozwiązujesz, pozwala korzystać z opcji współbieżnej, podejście blokowe może być szybsze. –

137

podejście blok unika działa algorytm odnośnika do każdy klucz:

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

Mimo że NSDictionary jest zaimplementowany jako hashtable (co oznacza, że ​​koszt wyszukiwania elementu wynosi O(1)), wyszukiwania wciąż spowalniają twoją iterację przez stały współczynnik.

Moje pomiary pokazują, że do słownika d liczb ...

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

... zsumowaniu cyfr z podejściem bloku ...

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

... zamiast podejście pętli ...

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

... jest ab obecnie o 40% szybszy.

EDIT: Nowy SDK (6.1+) wydaje się optymalizacji iteracji, tak podejście pętli jest o 20% krótszy niż podejście modułowe, przynajmniej dla prostego przypadku powyżej.

+0

A co z systemem iOS 10/11, który z nich jest szybszy? – Supertecnoboff

+0

elegancki, uwielbiam to! – YvesLeBorg

5

to iteracja stosując podejście bloku:

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

Z autouzupełniania jest bardzo szybkie ustawianie, i nie trzeba się martwić o pisanie iteracji kopertę.

+0

Dzięki .. Dobre rozwiązanie, jeśli potrzebujesz zmutować 'NSMutableDictionary' w procesie – jose920405