Gibt es eine Möglichkeit, ein Wörterbuch zu durchlaufen?

200

Ich weiß NSDictionariesals etwas, wo Sie eine brauchen key, um eine zu bekommen value. Aber wie kann ich über alles keysund valuesin a iterieren NSDictionary, damit ich weiß, welche Schlüssel es gibt und welche Werte es gibt? Ich weiß, dass es so etwas wie ein For-in-Loop- In gibt JavaScript. Gibt es etwas ähnliches in Objective-C?

Alex Cio
quelle
Danke für diesen Beitrag. Wenn Sie in der SwiftSyntax iterieren , lesen
Sie

Antworten:

322

Ja, NSDictionaryunterstützt die schnelle Aufzählung. Mit Objective-C 2.0 können Sie Folgendes tun:

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

Die alternative Methode (die Sie verwenden müssen, wenn Sie auf Mac OS X vor 10.5 abzielen, diese aber weiterhin auf 10.5 und iPhone verwenden können) ist die Verwendung von 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]);
Adam Rosenfield
quelle
2
ObjC moderne Syntax: NSLog (@ "key =% @ value =% @", key, myDict [key]);
Geowar
@Darthenius Aufgrund der jüngsten Optimierungen ist die schnelle Aufzählung zumindest in bestimmten Fällen wieder schneller als die blockbasierte. Wenn das von Ihnen gelöste Problem jedoch die gleichzeitige Option ermöglicht, ist der blockbasierte Ansatz möglicherweise schneller.
Zev Eisenberg
@ZevEisenberg Siehe das Ende meines Beitrags.
Rok Strniša
Hoppla, ich habe oben auf Ihren Link geklickt, um ihn in einem neuen Tab zu öffnen, und habe nicht einmal bemerkt, wer ihn geschrieben hat oder dass er sich auf derselben Seite befindet. Wenn Sie den obigen Kommentar noch bearbeiten können, möchten Sie dies möglicherweise tun, damit faule Leser nicht auf die falsche Idee kommen.
Zev Eisenberg
153

Der Blockansatz vermeidet das Ausführen des Suchalgorithmus für jeden Schlüssel :

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

Obwohl NSDictionarydie Implementierung als Hashtabelle implementiert ist (was bedeutet, dass die Kosten für die Suche nach einem Element hoch sind O(1)), verlangsamen Suchvorgänge Ihre Iteration um einen konstanten Faktor .

Meine Messungen zeigen, dass für ein Wörterbuch dder Zahlen ...

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

... die Zahlen mit dem Blockansatz zusammenfassen ...

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

... anstatt des Loop-Ansatzes ...

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

... ist ungefähr 40% schneller .

BEARBEITEN : Das neue SDK (6.1+) scheint die Schleifeniteration zu optimieren, sodass der Schleifenansatz jetzt etwa 20% schneller ist als der Blockansatz , zumindest für den obigen einfachen Fall.

Rok Strniša
quelle
Was ist mit iOS 10/11, welches ist schneller?
Supertecnoboff
elegant, liebe es!
YvesLeBorg
10

Dies ist eine Iteration unter Verwendung des Blockansatzes:

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

Die automatische Vervollständigung lässt sich sehr schnell einstellen, und Sie müssen sich keine Gedanken über das Schreiben des Iterationsumschlags machen.

Javier Calatrava Llavería
quelle
Danke .. Gute Lösung, wenn Sie das NSMutableDictionaryin dem Prozess mutieren müssen
jose920405