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.