2010-02-15 19 views
2

J'ai un NSArray de NSDictionaries. J'ai besoin de vérifier s'il y a au moins une occurrence d'un objet pour une clé du NSDictionary dans NSArray. Je le fais en utilisantMeilleure alternative pour vérifier l'existence de la clé de NSDictionary dans NSArray?

int i; 
for (i=0;i< [myArray count];i++) 
{ 
    if ([[[myArray objectAtIndex: i] objectForKey: myKey] isEqualToString: myString]) { 
     found = YES; 
     break; 
    } else { 
     found = NO; 
    } 
} 

Mais je soupçonne qu'il ya une meilleure/alternative plus rapide pour elle ...

Merci

Répondre

6

Ceci est aussi rapide que vous pouvez l'obtenir avec vos structures de données actuelles. Vous effectuez une recherche O (1) pour chaque dictionnaire du tableau. Si vous avez un grand nombre de dictionnaires, cela peut coûter cher, donc vous pouvez considérer (en fonction de la sémantique de vos données) en gardant un NSSet séparé qui contient l'ensemble des objets chaîne comprenant toutes les valeurs dans les dictionnaires. Ensuite, vous pouvez vérifier une fois dans cet ensemble pour l'existence.

Parlez-nous de la forme des données pour plus de perspicacité ...

aussi faire attention avec l'opérateur == avec NSString s. Si vous vérifiez réellement si le texte de la chaîne est égal, vous devriez utiliser -isEqualToString: à la place, car votre formulaire fera juste une comparaison de référence.

+0

Merci. Je l'ai changé en -isEqualToString :. Eh bien, le tableau peut être infiniment long mais aura généralement moins de 10 objets. Les dictionnaires ont toujours 4 paires. Une chaîne vide (je pourrais la changer à zéro plus tard), une image, un chemin (aussi une chaîne) et une autre chaîne. Je suppose que ça ne vaut pas la peine d'utiliser autre chose comme ça si le nombre est faible. J'ai posé la question pour voir s'il y avait une méthode pour cela ou quelque chose comme ça. Il fonctionne bien sur un faible nombre. Les deux autres commentaires ont dit quelque chose au sujet de l'énumération rapide qui est propre à avoir. Merci encore. – Jef

+0

Oui, il n'y a pas de structure de données miracle pour ce que vous voulez; vous obtenez juste des tableaux, des ensembles et des dictionnaires comme des blocs de construction. Si votre liste est généralement autour de 10 éléments, alors oui, iterating est essentiellement gratuit et vous n'avez pas besoin de complexifier les choses en faisant quelque chose de spécial. Votre implémentation est correcte et la syntaxe 'for..in' est un bon bonus. –

2

Utiliser == pour vérifier l'égalité de chaîne peut provoquer un comportement inattendu, parce que vous comparez des pointeurs (cela peut être correct si vous êtes sûr que vous avez affaire à un seul objet pointé par deux pointeurs). isEqualToString: est probablement ce que vous voulez à la place.

Vous pouvez utiliser « énumération rapide » pour simplifier les choses un peu:

bool found = NO; 

for (NSDictionary *dict in myArray) { 
    found = [[dict objectForKey:myKey] isEqualToString:myString]; 

    if (found) 
     break; 
} 

Il est seulement « plus vite » dans le sens où il est moins de mots à écrire; la vitesse d'exécution est la même.

+0

Merci pour votre réponse rapide. Je l'ai changé pour isEqualToString. – Jef

+3

"C'est seulement" plus rapide "dans le sens où il y a moins de mots à écrire; la vitesse d'exécution est la même. "Pas nécessairement. Si l'implémentation du tableau est une liste liée, alors l'énumération, que ce soit par énumération rapide ou NSEnumerator, sera plus rapide que l'itération vers le haut ou le bas vers un index croissant. (Ce n'est pas que vous devriez savoir ou vous soucier comment le tableau est implémenté.) –

+0

Notez qu'il devrait être "pour (NSDictionary * dict in myArray)" avec un * avant dict. – Jef

7

Oui. Utilisez "énumération rapide", communément aussi appelé boucle for-in:

for (NSDictionary* dict in myArray) { 

De plus, pour comparer l » NSString de, utilisez -isEqualToString:.

if ([[dict objectForKey: myKey] isEqualToString:myString]) { 

Cela dit, il n'y a pas d'amélioration algorithmiques à ce (par exemple cette méthode est déjà le meilleur.)

+0

Merci. Je l'ai changé pour isEqualToString. Je n'avais jamais utilisé l'énumération rapide auparavant. – Jef

5

Vous devez utiliser l'énumération rapide, qui itérer les objets à l'aide d'un tableau C dans les coulisses . En ce moment, vous appelez à la fois -objectAtIndex: et -count à chaque fois dans la boucle.

Vous pouvez également consulter NSPredicate si myKey est une chaîne. Mon instinct me dit que ce serait plus lent, mais vous ne savez jamais si elle peut bénéficier d'une optimisation interne pour NSDictionary:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%@ LIKE %@", myKey, myString]; 
BOOL found = ([[myArray filteredArrayUsingPredicate:predicate] count] > 0); 
3

Vous pourriez être beaucoup plus succinct avec codage clé-valeur:

[[myArray valueForKey:myKey] containsObject:myString]; 

Il est pas nécessairement plus rapide (je pense que ce sera plus lent), mais la vitesse n'est pas toujours la principale préoccupation. Si la vitesse est critique dans un cas particulier, c'est au profilage de décider.

1

Après avoir reçu votre objet, vous pouvez vérifier que votre objet reçu est "NSArray" ou "NSDictionary" ou "NSString" etc. Vous pouvez utiliser le code suivant pour vérifier votre objet.

if([obj isKindOfClass:[NSArray class]]){ 
    NSLog(@"IS NSArray"); 
} 
else if([obj isKindOfClass:[NSDictionary class]]){ 
    NSLog(@"Is NSDictionary"); 
} 
else 
{ 
    NSLog(@"Other"); 
} 
0

Avec énumération rapide

BOOL found; 

for (NSDictionary *dict in array) { 

     if ([[dict objectForKey:@"YOURKEY"] isEqualToString:@"YOURVALUE"]) { 
      found = YES; 
      break; 
     } else { 
      found = NO; 
     } 
    }