How to turn an NSArray of strings into an array of unique strings, in the same order?

cannyboy picture cannyboy · Nov 17, 2010 · Viewed 19.9k times · Source

If you have an NSArray of strings

{ @"ONE", @"ONE", @"ONE", "TWO", @"THREE", @"THREE" }

How would I turn that into

{ @"ONE", @"TWO", @"THREE" }

..where the array follows the same order as the original. I think that you can turn an array into an NSSet to get unique items, but if you turn it back into an array you are not guaranteed to get the same order..

Answer

Dave DeLong picture Dave DeLong · Nov 17, 2010

My initial thought was that you could do:

NSArray * a = [NSArray arrayWithObjects:@"ONE", @"ONE", @"ONE", @"TWO", @"THREE", @"THREE", nil];
NSLog(@"%@", [a valueForKeyPath:@"@distinctUnionOfObjects.self"]);

But that does not maintain order. Therefore, you have to do it manually:

NSArray * a = [NSArray arrayWithObjects:@"ONE", @"ONE", @"ONE", @"TWO", @"THREE", @"THREE", nil];
NSMutableArray * unique = [NSMutableArray array];
NSMutableSet * processed = [NSMutableSet set];
for (NSString * string in a) {
  if ([processed containsObject:string] == NO) {
    [unique addObject:string];
    [processed addObject:string];
  }
}

I use an NSMutableSet for determining if I've already come across this entry before (as opposed to [unique containsObject:string], since a set will have O(1) lookup time, and an array has O(n) lookup time. If you're only dealing with a small number of objects, then this won't matter. However, if the source array is very large, then using the set to determine uniqueness may add a bit of a speed boost. (however, you should use Instruments to profile your code and see if it's necessary)