56

I have an NSArray formed with objects of a custom class. The class has 3 (city, state, zip) string properties. I would like to get all unique state values from the array.

I did read through the NSPredicate class but couldn't make much of how to use it in this case. The only examples I could find were for string operations.

Can someone please help me out?

Girish
  • 4,692
  • 4
  • 35
  • 55
lostInTransit
  • 70,519
  • 61
  • 198
  • 274

2 Answers2

136

Take a look at keypaths. They are super powerful and I use them instead of NSPredicate classes most of the time. Here is how you would use them in your example...

NSArray *uniqueStates;
uniqueStates = [customObjects valueForKeyPath:@"@distinctUnionOfObjects.state"];

Note the use of valueForKeyPath instead of valueForKey.

Here is a more detailed/contrived example...

NSDictionary *arnold = [NSDictionary dictionaryWithObjectsAndKeys:@"arnold", @"name", @"california", @"state", nil];
NSDictionary *jimmy = [NSDictionary dictionaryWithObjectsAndKeys:@"jimmy", @"name", @"new york", @"state", nil];
NSDictionary *henry = [NSDictionary dictionaryWithObjectsAndKeys:@"henry", @"name", @"michigan", @"state", nil];
NSDictionary *woz = [NSDictionary dictionaryWithObjectsAndKeys:@"woz", @"name", @"california", @"state", nil];

NSArray *people = [NSArray arrayWithObjects:arnold, jimmy, henry, woz, nil];

NSLog(@"Unique States:\n %@", [people valueForKeyPath:@"@distinctUnionOfObjects.state"]);

// OUTPUT
// Unique States:
// "california",
// "michigan",
// "new york"
sbonami
  • 1,892
  • 17
  • 33
probablyCorey
  • 2,478
  • 2
  • 16
  • 17
124

The totally simple one liner:

NSSet *uniqueStates = [NSSet setWithArray:[myArrayOfCustomObjects valueForKey:@"state"]];

The trick is the valueForKey: method of NSArray. That will iterate through your array (myArrayOfCustomObjects), call the -state method on each object, and build an array of the results. We then create an NSSet with the resulting array of states to remove duplicates.


Starting with iOS 5 and OS X 10.7, there's a new class that can do this as well: NSOrderedSet. The advantage of an ordered set is that it will remove any duplicates, but also maintain relative order.

NSArray *states = [myArrayOfCustomObjects valueForKey:@"state"];
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:states];
NSSet *uniqueStates = [orderedSet set];
Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • While I also like the power of @distinctUnionOfObjects, and hence, the answer user probablyCorey gave, the benefit with this concise approach here in this solution is that ordering is preserved. – idStar Jan 29 '16 at 18:56