0

I have 2 arrays, one of which is NSMutableArray (say mutArrayA) and other is NSArray(arrayB). I am appending arrayB to mutArrayA and at the same time I want to remove duplicates if any i.e. I don't want any duplicates in mutArrayA.

One way I know to do this is iterating over each object in the arrayB and checking its index using indexOfObject which if found in mutArrayA, then don't append that object to mutArrayA else append it. However I was trying to look for some quicker way to do this and I came across the following solution on this site which goes as below:

[mutArrayA setArray:[[NSSet setWithArray:arrayB] allObjects]];

When I execute this, my mutArrayA gets replaced with objects in arrayB because of setArray. Is there a quicker way using which I can append the array without getting the duplicates.

7 Answers 7

2
[mutArrayA addObjectsFromArray:[[NSSet setWithArray:arrayB] allObjects]];
[mutArrayA setArray:[[NSSet setWithArray:mutArrayA] allObjects]];

So initially you remove duplicates from arrayB, append it, and then apply the same principle to remove duplicates from mutArrayA if there are any after appending

UPDATE

You need to override isEqual: method for your class. I'll give you an example by assuming your objects contain NSString objects.

- (BOOL)isEqual:(MyClass *)object
{
  return [self.key isEqualToString:object.key] && [self.value isEqualToString:object.value];
}

You need also to override hash method like this:

- (NSUInteger)hash {
return [self.key hash] ^ [self.value hash];
}

The problem is NSSet doesn't remove duplicates cause it thinks they're are not duplicates so by overriding this method you give it a clue of how to compare your objects for equality

Sign up to request clarification or add additional context in comments.

12 Comments

This didn't work for me. Its giving me duplicates in mutArrayA after I run the code.
So any idea how does the NSSet check for the duplicate? Does it check the contents of the object or its pointer value?
i suppose it checks their hash value
Hmmm then that could be reason its not working for me.
There is a key distinction you should make here. When you say duplicates do you mean in an isEqual sense, or has equal values? You may need to override your isEqual method to get the behavior you're going after. Have a look at this code.
|
1

Implement the following method and invoke it using your array to be traversed.

- (NSMutableArray *)removeDuplicates:(NSMutableArray *)array{
    NSArray *copy = [array copy];
    NSInteger index = [copy count] - 1;
    for (id object in [copy reverseObjectEnumerator]) {
        if ([array indexOfObject:object inRange:NSMakeRange(0, index)] != NSNotFound) {
            [array removeObjectAtIndex:index];
        }
        index--;
    }
    [copy release];
    copy = nil;
    return array;
}

Comments

0

Try this,

[mutArrayA addObjectsFromArray: arrayB];
[mutArrayA setArray:[[NSSet setWithArray:mutArrayA] allObjects]];

Comments

0

Put both arrays into a set which will remove duplicates, but will not guarantee order. If order is important then another solution will need to be used.

NSMutableSet *set = [[NSMutableSet alloc] init];
[set addObjectsFromArray:mutArrayA];
[set addObjectsFromArray:arrayB];

mutArrayA = [[set allObjects] mutableCopy];

4 Comments

By order do you mean sort order? I am sorting mutArrayA after appending, so that shouldn't be an issue I guess
However I will give your solution a try to understand how it works.
An NSSet/NSMutableSet will hold an unordered collection of distinct objects. So the objects won't be located at a distinct index and won't come out of the set in the same order every time. Sorting the array after retrieving it from the set will work fine.
Nopes this solution also didn't help me. I wonder if its the format of the data thats creating the issue or maybe [set allObjects] could be checking the pointer value of the objects. The data I have inside both the arrays is of this format: <myClass 0x16c38af0> { key = Testing 123; value = Testing the app },
0

There is a key distinction you should make here. When you say duplicates do you mean in an isEqual sense, or has equal values? You may need to override your isEqual method to get the behavior you're going after. If you are using custom objects, by default your custom objects are only equal if they have the same pointer reference. ie.

[[[MyCustomObject alloc]init]isEqual:[[MyCustomObject alloc]init]] == No;

Whereas 

[[[NSString alloc] init] isEqual:[[NSString alloc] init]] == YES;

Assuming you are correctly handling isEqual (or implementing your own method to determine equality) you could convert your array to an NSSet and then back as previously suggested.

NSSet *compositeSet = [NSSet setWithArray:[mutArrayA addObjectsFromArray:mutArrayB]];
NSArray *deduplicatedArray = [compositeSet allObjects];

Comments

0

The KVC Object Operator @distinctUnionOfObjects might be helpful here.

[mutArrayA addObjectsFromArray:arrayB];
uniquearray = [mutArrayA valueForKeyPath:@"@distinctUnionOfObjects.self"];

Here's an NSArray category for getting a distinct array.

Comments

0

This might not apply to the original poster's question, but this page was the first search result for the terms I used, so I'm posting my solution here in case it helps someone else.

I wanted to merge two arrays of NSStrings (which were both being used as keys in NSDictionaries), but I needed to keep the sort order of the first array. So I wanted an array that was made up of the sorted array, plus any unique values in the second array. I used the following code:

NSArray *sortedArray = @[@"Aardvark", @"Bandicoot", @"Catbird", @"Dingo", @"Elephant shrew", @"Flagellate"];
NSArray *array2 = @[@"Zebra", @"Aardvark", @"Yak", @"Dingo", @"Xeromys"];

NSMutableArray *nonDupes = [NSMutableArray arrayWithArray:array2];
[nonDupes removeObjectsInArray:sortedArray];
NSArray *combinedArray = [sortedArray arrayByAddingObjectsFromArray:nonDupes];

NSLog(@"combinedArray: %@", combinedArray);

Output:

2017-05-01 14:46:39.860 App [23038:6945531] combinedArray: (
    Aardvark,
    Bandicoot,
    Catbird,
    Dingo,
    "Elephant shrew",
    Flagellate,
    Zebra,
    Yak,
    Xeromys
)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.