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

This question is related to ios objective-c nsmutablearray

The answer is


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


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

As AnthoPak also noted it is possible to remove duplicates based on a property. An example would be: @distinctUnionOfObjects.name


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.


Remove duplicate values from NSMutableArray in Objective-C

NSMutableArray *datelistArray = [[NSMutableArray alloc]init];
for (Student * data in fetchStudentDateArray)
{
    if([datelistArray indexOfObject:data.date] == NSNotFound)
    [datelistArray addObject:data.date];
}

Here is the code of removing duplicates values from NSMutable Array..it 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

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


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

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


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

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.


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


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

Examples related to ios

Adding a UISegmentedControl to UITableView Crop image to specified size and picture location Undefined Symbols error when integrating Apptentive iOS SDK via Cocoapods Keep placeholder text in UITextField on input in IOS Accessing AppDelegate from framework? Autoresize View When SubViews are Added Warp \ bend effect on a UIView? Speech input for visually impaired users without the need to tap the screen make UITableViewCell selectable only while editing Xcode 12, building for iOS Simulator, but linking in object file built for iOS, for architecture arm64

Examples related to objective-c

Adding a UISegmentedControl to UITableView Keep placeholder text in UITextField on input in IOS Accessing AppDelegate from framework? Warp \ bend effect on a UIView? Use NSInteger as array index Detect if the device is iPhone X Linker Command failed with exit code 1 (use -v to see invocation), Xcode 8, Swift 3 ITSAppUsesNonExemptEncryption export compliance while internal testing? How to enable back/left swipe gesture in UINavigationController after setting leftBarButtonItem? Change status bar text color to light in iOS 9 with Objective-C

Examples related to nsmutablearray

'Invalid update: invalid number of rows in section 0 How do I convert NSMutableArray to NSArray? The best way to remove duplicate values from NSMutableArray in Objective-C? How do I sort an NSMutableArray with custom objects in it?