2011-09-30 4 views
3

J'ai deux nssets.Comment comparer deux NSSets basés sur des attributs d'objets?

nsset1: person.id = 1, person.id = 2, person.id = 3 
nsset2: person.id = 1, person.id = 2 

Les résultats doivent être:

nsset1 - nsset2: person (with id 3) 
nsset2 - nsset1: null 

Ces objets avec le même identifiant dans ces deux ensembles sont des objets différents, donc je ne pouvais pas simplement faire minusSet.

Je veux faire quelque chose comme:

nsset1: person.id = 1, person.id = 2, person.id = 3 
nsset2: person.id = 4, person.id = 5 

Les résultats devraient ressembler à ceci:

nsset1 - nsset2: person (id 1), person (id 2), person (id 3) 
nsset2 - nsset1: person (id 4), person (id 5) 

Quelle est la meilleure façon de le faire?

Répondre

5

Vous devriez essayer quelque chose comme ça

NSSet* nsset1 = [NSSet setWithObjects:person_with_id_1, person_with_id_2, person_with_id_3, nil]; 
NSSet* nsset2 = [NSSet setWithObjects:person_with_id_2, person_with_id_4, nil]; 

// retrieve the IDs of the objects in nsset2 
NSSet* nsset2_ids = [nsset2 valueForKey:@"objectID"]; 
// only keep the objects of nsset1 whose 'id' are not in nsset2_ids 
NSSet* nsset1_minus_nsset2 = [nsset1 filteredSetUsingPredicate: 
    [NSPredicate predicateWithFormat:@"NOT objectID IN %@",nsset2_ids]]; 
+0

cela ressemble à goot mais j'obtiens une erreur comme "raison:" Impossible d'analyser la chaîne de format "objectID NOT IN% @" 'J'ai utilisé' objectID' parce que c'est le vrai nom de l'attribut de ces objets. tout avant de filtrer avant semble bien, je reçois les identifiants et ainsi de suite. une idée? – choise

+0

Yep désolé n'a pas testé ma réponse avant. Le [Predicate Programming Guide] (http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html) indique que l'opérateur 'NOT' s'applique à une expression entière (et pas un autre opérateur comme l'opérateur 'IN' directement), nous devrions donc écrire' NOT objectID IN% @ 'au lieu de' objectID NOT IN% @ '. J'ai mis à jour ma réponse en conséquence. – AliSoftware

+0

oui aussi obtenu avec 'NOT (objectID IN% @)' je pense – choise

8

@ réponse de AliSoftware est une approche intéressante. NSPredicate est assez lent en dehors des données de base, mais c'est souvent bien. Si la performance est un problème, vous pouvez implémenter le même algorithme avec une boucle, qui est un peu plus de lignes de code, mais généralement plus rapide.

Une autre approche consiste à demander si deux personnes ayant le même ID doivent toujours être considérées comme équivalentes. Si cela est vrai, alors vous pouvez remplacer isEqual: et hash pour votre classe personne comme celui-ci (en supposant identifier est un NSUInteger):

- (BOOL)isEqual:(id)other { 
    if ([other isMemberOfClass:[self class]) { 
    return ([other identifier] == [self identifier]); 
    } 
    return NO; 
} 

- (NSUInteger)hash { 
    return [self identifier]; 
} 

Faire cela, toutes les opérations NSSet traiteront des objets avec le même identifiant égal, vous peut utiliser minusSet. Aussi NSMutableSet addObject: sera automatiquement unique pour vous sur l'identifiant.

La mise en œuvre de isEqual: et de hash a de vastes répercussions, vous devez donc vous assurer que chaque fois que vous rencontrez des objets de deux personnes avec le même identificateur, ils doivent être traités comme égaux. Mais si c'est votre cas, cela simplifie grandement et accélère votre code.

Questions connexes