简体   繁体   中英

How to compare two NSSets based on attributes of objects?

I have two nssets.

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

Results should be:

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

These objects with the same id in those two sets are different objects, so I couldn't simply do minusSet.

I want to do something like:

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

Results should be like this:

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

What is the best way to do this?

@AliSoftware's answer is an interesting approach. NSPredicate is pretty slow outside of Core Data, but that often is fine. If the performance is a problem, you can implement the same algorithm with a loop, which is a few more lines of code, but generally faster.

Another approach is to ask whether two persons with the same ID should always be considered equivalent. If that's true, then you can override isEqual: and hash for your person class like this (assuming identifier is an NSUInteger):

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

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

Doing this, all NSSet operations will treat objects with the same identifier as equal, so you can use minusSet . Also NSMutableSet addObject: will automatically unique for you on identifier.

Implementing isEqual: and hash has broad-reaching impacts, so you need to make sure that everyplace you encounter two person objects with the same identifier, they should be treated as equal. But if that's you case, this does greatly simplify and speed up your code.

You should try something like this

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM