Czy istnieje sposób na iterację słownika?


200

Wiem NSDictionariesjako coś, czego potrzebujesz key, aby uzyskać value. Ale w jaki sposób można iteracyjne nad wszystkim keysi valuesw sposób NSDictionary, tak, że wiem, co klucze istnieją, i jakie wartości są? Wiem, że jest coś o nazwie dla w pętli w JavaScript. Czy jest coś podobnego Objective-C?


Dziękuję za ten post. Jeśli iterujesz w Swiftskładni, zapoznaj się z tym postem: stackoverflow.com/a/24111700/419348
AechoLiu

Odpowiedzi:


323

Tak, NSDictionaryobsługuje szybkie wyliczanie. Z Objective-C 2.0 możesz 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]);

Alternatywną metodą (której musisz użyć, jeśli celujesz w Mac OS X w wersji wcześniejszej niż 10.5, ale nadal możesz korzystać z wersji 10.5 i iPhone'a), to 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
Nowoczesna składnia ObjC: NSLog (@ "klucz =% @ wartość =% @", klucz, myDict [klucz]);
geowar

@Darthenius ze względu na ostatnie optymalizacje, szybkie wyliczanie jest znowu szybsze niż oparte na blokach, przynajmniej w niektórych przypadkach. Ale jeśli rozwiązywany problem pozwala na użycie opcji równoczesnej, podejście oparte na blokach może być szybsze.
Zev Eisenberg,

@ZevEisenberg Zobacz koniec mojego postu.
Rok Strniša

Ups, kliknąłem powyższy link, aby otworzyć w nowej karcie, i nawet nie zauważyłem, kto go napisał lub czy jest na tej samej stronie. Jeśli nadal możesz edytować powyższy komentarz, możesz chcieć, aby leniwi czytelnicy nie wpadli na zły pomysł.
Zev Eisenberg,

153

Podejście blokowe pozwala uniknąć uruchamiania algorytmu wyszukiwania dla każdego klucza :

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

Mimo że NSDictionaryjest implementowany jako tablica mieszająca (co oznacza, że ​​koszt wyszukiwania elementu wynosi O(1)), wyszukiwania wciąż spowalniają twoją iterację o stały czynnik .

Moje pomiary pokazują, że dla słownika dliczb ...

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

... sumując liczby z podejściem blokowym ...

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

... zamiast podejścia w pętli ...

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

... jest około 40% szybszy .

EDYCJA : Nowy zestaw SDK (6.1+) wydaje się optymalizować iterację pętli, więc podejście do pętli jest teraz około 20% szybsze niż podejście do bloku , przynajmniej w powyższym prostym przypadku.


Co z iOS 10/11, który jest szybszy?
Supertecnoboff

elegancki, uwielbiam to!
YvesLeBorg

10

Oto iteracja przy użyciu podejścia blokowego:

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

Dzięki autouzupełnianiu jest bardzo szybki do ustawienia i nie musisz się martwić pisaniem koperty iteracyjnej.


Dzięki .. Dobre rozwiązanie, jeśli potrzebujesz zmutować NSMutableDictionaryproces
jose920405
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.