The best way to remove duplicate values from NSMutableArray in Objective-C?

The best way to remove duplicate values from NSMutableArray in Objective-C?

The best way to remove duplicate values (NSString) from NSMutableArray in Objective-C?

Is this the easiest and right way to do it?

uniquearray = [[NSSet setWithArray:yourarray] allObjects]; 

only character - not special/numbers from keyboard - iPhone


iphone web page transitions
Your NSSet approach is the best if you're not worried about the order of the objects, but then again, if you're not worried about the order, then why aren't you storing them in an NSSet to begin with?.
How to open a new view when touching on a uiview?
I wrote the answer below in 2009; in 2011, Apple added NSOrderedSet to iOS 5 and Mac OS X 10.7.

UITableView Swipe to delete: how to customize button and action?
What had been an algorithm is now two lines of code:.
How do you get an iPhone's Device Name in C#
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray]; NSArray *arrayWithoutDuplicates = [orderedSet array]; 
If you are worried about the order and you're running on iOS 4 or earlier, loop over a copy of the array:.
How do you get the viewport scale after pinch/zoom on an iPhone web app?
NSArray *copy = [mutableArray copy]; NSInteger index = [copy count] - 1; for (id object in [copy reverseObjectEnumerator]) {     if ([mutableArray indexOfObject:object inRange:NSMakeRange(0, index)] != NSNotFound) {         [mutableArray removeObjectAtIndex:index];     }     index--; } [copy release]; Mobile implementation on IPhone, Blackberry and other mobile devices

Using an Objective-C++ file from a C++ file


I know this is an old question, but there is a more elegant way to remove duplicates in a NSArray if you don't care about the order.. If we use Object Operators from Key Value Coding we can do this:.
uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"]; 


Yes, using NSSet is a sensible approach.. To add to Jim Puls' answer, here's an alternative approach to stripping duplicates while retaining order:.
// Initialise a new, empty mutable array  NSMutableArray *unique = [NSMutableArray array];  for (id obj in originalArray) {     if (![unique containsObject:obj]) {         [unique addObject:obj];     } } 
It's essentially the same approach as Jim's but copies unique items to a fresh mutable array rather than deleting duplicates from the original.

This makes it slightly more memory efficient in the case of a large array with lots of duplicates (no need to make a copy of the entire array), and is in my opinion a little more readable.. Note that in either case, checking to see if an item is already included in the target array (using containsObject: in my example, or indexOfObject:inRange: in Jim's) doesn't scale well for large arrays.

Those checks run in O(N) time, meaning that if you double the size of the original array then each check will take twice as long to run.

Since you're doing the check for each object in the array, you'll also be running more of those more expensive checks.

The overall algorithm (both mine and Jim's) runs in O(N2) time, which gets expensive quickly as the original array grows.. To get that down to O(N) time you could use a NSMutableSet to store a record of items already added to the new array, since NSSet lookups are O(1) rather than O(N).

In other words, checking to see whether an element is a member of an NSSet takes the same time regardless of how many elements are in the set.. Code using this approach would look something like this:.
NSMutableArray *unique = [NSMutableArray array]; NSMutableSet *seen = [NSMutableSet set];  for (id obj in originalArray) {     if (![seen containsObject:obj]) {         [unique addObject:obj];         [seen addObject:obj];     } } 
This still seems a little wasteful though; we're still generating a new array when the question made clear that the original array is mutable, so we should be able to de-dupe it in place and save some memory.

Something like this:.
NSMutableSet *seen = [NSMutableSet set]; NSUInteger i = 0;  while (i < [originalArray count]) {     id obj = [originalArray objectAtIndex:i];      if ([seen containsObject:obj]) {         [originalArray removeObjectAtIndex:i];         // NB: we *don't* increment i here; since         // we've removed the object previously at         // index i, [originalArray objectAtIndex:i]         // now points to the next object in the array. 

} else { [seen addObject:obj]; i++; } }
UPDATE: Yuri Niyazov pointed out that my last answer actually runs in O(N2) because removeObjectAtIndex: probably runs in O(N) time.

. (He says "probably" because we don't know for sure how it's implemented; but one possible implementation is that after deleting the object at index X the method then loops through every element from index X+1 to the last object in the array, moving them to the previous index.

If that's the case then that is indeed O(N) performance.)
. So, what to do? It depends on the situation.

If you've got a large array and you're only expecting a small number of duplicates then the in-place de-duplication will work just fine and save you having to build up a duplicate array.

If you've got an array where you're expecting lots of duplicates then building up a separate, de-duped array is probably the best approach.

The take-away here is that big-O notation only describes the characteristics of an algorithm, it won't tell you definitively which is best for any given circumstance..


Available in OS X v10.7 and later.. If you are worried about the order,right way to do .
NSArray *no = [[NSOrderedSet orderedSetWithArray:originalArray]allObjects]; 
Here is the code of removing duplicates values from NSArray in Order..


If you are targeting iOS 5+ (what covers the whole iOS world), best use NSOrderedSet.

It removes duplicates and retains the order of your NSArray.. Just do.
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray]; 
You can now convert it back to a unique NSArray.
NSArray *uniqueArray = orderedSet.array; 
Or just use the orderedSet because it has the same methods like an NSArray like objectAtIndex:, firstObject and so on.. A membership check with contains is even faster on the NSOrderedSet than it would be on an NSArray. For more checkout the NSOrderedSet Reference.


need order .
NSArray *yourarray = @[@"a",@"b",@"c"]; NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourarray]; NSArray *arrayWithoutDuplicates = [orderedSet array]; NSLog(@"%@",arrayWithoutDuplicates); 
or don't need order.
NSSet *set = [NSSet setWithArray:yourarray]; NSArray *arrayWithoutOrder = [set allObjects]; NSLog(@"%@",arrayWithoutOrder); 


Note that if you have a sorted array, you don't need to check against every other item in the array, just the last item.

This should be much faster than checking against all items..
// sortedSourceArray is the source array, already sorted NSMutableArray *newArray = [[NSMutableArray alloc] initWithObjects:[sortedSourceArray objectAtIndex:0]]; for (int i = 1; i < [sortedSourceArray count]; i++) {     if (![[sortedSourceArray objectAtIndex:i] isEqualToString:[sortedSourceArray objectAtIndex:(i-1)]])     {         [newArray addObject:[tempArray objectAtIndex:i]];     } } 
It looks like the NSOrderedSet answers that are also suggested require a lot less code, but if you can't use an NSOrderedSet for some reason, and you have a sorted array, I believe my solution would be the fastest.

I'm not sure how it compares with the speed of the NSOrderedSet solutions.

Also note that my code is checking with isEqualToString:, so the same series of letters will not appear more than once in newArray.

I'm not sure if the NSOrderedSet solutions will remove duplicates based on value or based on memory location.. My example assumes sortedSourceArray contains just NSStrings, just NSMutableStrings, or a mix of the two.

If sortedSourceArray instead contains just NSNumbers or just NSDates, you can replace .
if (![[sortedSourceArray objectAtIndex:i] isEqualToString:[sortedSourceArray objectAtIndex:(i-1)]]) 
with .
if ([[sortedSourceArray objectAtIndex:i] compare:[sortedSourceArray objectAtIndex:(i-1)]] != NSOrderedSame) 
and it should work perfectly.

If sortedSourceArray contains a mix of NSStrings, NSNumbers, and/or NSDates, it will probably crash..


There's a KVC Object Operator that offers a more elegant solution uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"]; Here's an NSArray category.



One more simple way you can try out which will not add duplicate Value before adding object in array:-. //Assume mutableArray is allocated and initialize and contains some value.
if (![yourMutableArray containsObject:someValue]) {    [yourMutableArray addObject:someValue]; } 


Here i removed duplicate name values from mainArray and store result in NSMutableArray(listOfUsers).
for (int i=0; i<mainArray.count; i++) {     if (listOfUsers.count==0) {         [listOfUsers addObject:[mainArray objectAtIndex:i]];      }    else if ([[listOfUsers valueForKey:@"name" ] containsObject:[[mainArray objectAtIndex:i] valueForKey:@"name"]])     {          NSLog(@"Same object");     }     else     {         [listOfUsers addObject:[mainArray objectAtIndex:i]];     } } 


Here is the code of removing duplicates values from NSMutable will work for you.

myArray is your Mutable Array that you want to remove duplicates values...
for(int j = 0; j < [myMutableArray count]; j++){     for( k = j+1;k < [myMutableArray count];k++){     NSString *str1 = [myMutableArray objectAtIndex:j];     NSString *str2 = [myMutableArray objectAtIndex:k];     if([str1 isEqualToString:str2])         [myMutableArray removeObjectAtIndex:k];     }  } // Now print your array and will see there is no repeated value 


Using Orderedset will do the trick.

This will keep the remove duplicates from the array and maintain order which sets normally doesn't do.


just use this simple code :.
NSArray *hasDuplicates = /* (...) */; NSArray *noDuplicates = [[NSSet setWithArray: hasDuplicates] allObjects]; 
since nsset doesn't allow duplicate values and all objects returns an array.

68 out of 100 based on 43 user ratings 1168 reviews