Existe uma maneira de iterar sobre um dicionário?

200

Eu sei NSDictionariescomo algo em que você precisa de um keypara obter um value. Mas como posso iterar tudo keyse valuesem um NSDictionary, para que eu saiba quais chaves existem e quais valores existem? Eu sei que há uma coisa chamada para-in-circuito no JavaScript. Existe algo semelhante Objective-C?

Alex Cio
fonte
Obrigado por este post. Se a iteração na Swiftsintaxe, consulte este post: stackoverflow.com/a/24111700/419348
AechoLiu

Respostas:

323

Sim, NSDictionarysuporta enumeração rápida. Com o Objective-C 2.0, você pode fazer isso:

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

O método alternativo (que você deve usar se tiver como alvo o Mac OS X pré-10.5, mas ainda pode usar o 10.5 e o iPhone) é usar um 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
fonte
2
Sintaxe moderna ObjC: NSLog (@ "chave =% @ valor =% @", chave, myDict [chave]);
68513 geowar
@Darthenius devido a otimizações recentes, a enumeração rápida é novamente mais rápida que a baseada em blocos, pelo menos em certos casos. Mas se o problema que você está solucionando permite usar a opção simultânea, a abordagem baseada em blocos pode ser mais rápida.
Zev Eisenberg
@ZevEisenberg Veja o final da minha postagem.
Rok Strniša
Ops, cliquei no seu link, acima, para abrir uma nova guia e nem percebi quem o escreveu ou que estava nessa mesma página. Se você ainda pode editar o comentário acima, convém fazê-lo, para que os leitores preguiçosos não entendam errado.
Zev Eisenberg
153

A abordagem de bloco evita a execução do algoritmo de pesquisa para cada chave :

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

Embora NSDictionaryseja implementado como uma hashtable (o que significa que o custo de procurar um elemento é O(1)), as pesquisas ainda diminuem sua iteração por um fator constante .

Minhas medidas mostram que, para um dicionário dde números ...

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

... resumindo os números com a abordagem de bloco ...

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

... em vez da abordagem de loop ...

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

... é cerca de 40% mais rápido .

EDIT : O novo SDK (6.1+) parece otimizar a iteração de loop, portanto, a abordagem de loop é agora cerca de 20% mais rápida que a abordagem de bloco , pelo menos no caso simples acima.

Rok Strniša
fonte
E no iOS 10/11, qual é o mais rápido?
Supertecnoboff
elegante, adoro!
YvesLeBorg 15/09
10

Esta é a iteração usando a abordagem de bloco:

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

O preenchimento automático é muito rápido de configurar, e você não precisa se preocupar em escrever o envelope da iteração.

Javier Calatrava Llavería
fonte
Thanks .. boa solução se você precisa transformar o NSMutableDictionaryno processo
jose920405