1

I have a class Person, which has a property firstname. Person objects are then added to an allPeople NSMutableArray in another class:

 @interface class1 : NSObject

@property (nonatomic, strong) NSMutableArray *allPeople;

You then have a method inside 'class1' which determines whether the firstname property of a Person object in the array is the same as another firstname property in the array.

This is where I'm stuck, essentially there's only ever going to be five person objects which need to be compared.

What I'd like to do is the following:-

-(BOOL)samefirstname{
    //i don't want to tamper with the original allPeople array so i make a mutable copy
    NSMutableArray *tempallpeople = [self.allPeople mutableCopy];
    for every person object in [tempallpeople]{
    if(person1.firstname == person2.firstname || or person1.firstname == person3.firstname || person1.firstname == person4.firstname || or person1.firstname == person5.firstname{
       return YES;   
     }else if (person2.firstname ect ect.

If anybody could shed some light on my issue that would be great.

1
  • 1
    Instead of comparing pointer values, compare content using: [person1.firstname isEqualToString: person2.firstname]. Commented Jul 29, 2014 at 19:39

6 Answers 6

4

You can use -[NSArray valueForKey:] to get the values of a particular property for each object in the array. An NSSet is a collection that contains a group of objects with no duplicates. If you create a set from the array of first names and they are the same size, then you have no duplicates.

- (BOOL)haveDuplicateFirstNames
{
    NSArray * firstNames = [[self allPeople] valueForKey:@"firstname"];
    return [firstNames count] != [[NSSet setWithArray:firstNames] count];
}
Sign up to request clarification or add additional context in comments.

Comments

3

Extract the names into a set and if the count of the set is different to the count of the people then there is a duplicate name.

Note that this will be an exact match (case and diacritic sensitive) and won't tell you which the duplicate is.

NSArray *names = [self.allPeople valueForKey:@"firstname"];
NSSet *filteredNames = [NSSet setWithArray:names];

return (names.count != filteredNames.count);

Comments

1

It's not clear if you want to find duplicate names or if you want to check if a name is already on the array, so here's both:

-(BOOL)hasName:(NSString*)name{

    if([self.allPeople indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {

        if([[obj firstname] isEqualToString:name]){
            *stop = YES;
            return YES;
        }

        return NO;

    }] != NSNotFound){
        return YES; // user with that name already exists
    }
    else{
        return NO; // name does not exists
    }
}

-(BOOL)hasDuplicateName{

    for(id first_object in self.allPeople){

        if([self.allPeople indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {

            if([[obj firstname] isEqualToString:[first_object firstname]] && obj != first_object){
                *stop = YES;
                return YES;
            }

            return NO;

        }] != NSNotFound){
           return YES; // user with that name already exists
        }
        else{
           return NO; // name does not exists
        }

    }
}

Change the "id" type to your Person class, and that should work.

Comments

1

This is really more of a comment than an answer, but here's a way you could further generalize the functionality described by @JoshCaswell and @Wain, should you ever need to do the same check in more than one place. First, add a method in a category on NSArray to perform the test for duplicates:

@implementation NSArray (XYZAdditions)

- (BOOL)xyz_hasDuplicateValuesForKey:(NSString *)key
{
    NSArray *allValues = [self valueForKey:key];
    NSSet *uniqueValues = [NSSet setWithArray:allValues];

    return allValues.count > uniqueValues.count;
}

@end

Then you can call the method whenever you wish to check for duplicate properties of objects in any given array. For example the code below...

NSArray *people = @[ [[Person alloc] initWithFirstName:@"Fred" lastName:@"Smith" age:22],
                     [[Person alloc] initWithFirstName:@"Sue" lastName:@"Smith" age:28],
                     [[Person alloc] initWithFirstName:@"Bill" lastName:@"Brown" age:28]];

NSLog(@"Duplicate first names? %@", [people xyz_hasDuplicateValuesForKey:@"firstName"] ? @"Yes" : @"No");
NSLog(@"Duplicate last names? %@", [people xyz_hasDuplicateValuesForKey:@"lastName"] ? @"Yes" : @"No");
NSLog(@"Duplicate ages? %@", [people xyz_hasDuplicateValuesForKey:@"age"] ? @"Yes" : @"No");

...results in the following output:

2014-07-29 16:14:56.031 xctest[4588:303] Duplicate first names? No
2014-07-29 16:14:56.031 xctest[4588:303] Duplicate last names? Yes
2014-07-29 16:14:56.031 xctest[4588:303] Duplicate ages? Yes

Comments

0
BOOL firstNameIsUnique = YES;
for (Person *person1 in allPersons) {
    for (Person *person2 in allPersons) {
        if (person1 != person2 && [person1.firstName isEqualToString:person2.firstName]) {
            firstNameIsUnique = NO;
            break;
        }
    }
    if (!firstNameIsUnique) break;
}

You enumerate through the array, and for each person in the array, you enumerate again through the array to see if the first names match. If a match is found, a BOOL is set and the code breaks out from the enumeration.

Please note that you cannot compare two objects using ==. Read up on pointers for the explanation.

Also note that this isn't exactly the most correct answer. The ones suggesting the use of sets are better.

3 Comments

person1 and person2 are the same object on the first iteration of each loop.
Are you sure you can put break statements in fast enumeration loops? I think it is not possible in this case?
@Pavlusha Yes, you can break out of objc fast enumeration.
0

You want to find out if the array contains two Person objects with the same name, right?

Do this:

BOOL contains = NO;

for (int i = 0; i < [self.allPeople count]; ++i) {
  for (int j = 0; j < i; ++j) {
    Person *p1 = (Person *) self.allPeople[i];
    Person *p2 = (Person *) self.allPeople[j];

    if ([p1.name isEqualToString:p2.name]) {
      contains = YES;
      break;
    }
  } 

  if (contains) { break; }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.