How to compare two NSArrays for equal content in any order?

22,858

Solution 1

Those two arrays are not equal. Two arrays are equal is they both have the same objects in the same order.

If you want to compare with no regard to order then you need to use two NSSet objects.

NSSet *set1 = [NSSet setWithArray:arr1];
NSSet *set2 = [NSSet setWithArray:arr2];

if ([set1 isEqualToSet:set2]) {
    // equal
}

Solution 2

Most of the answers here actually do not work for fairly common cases (see their comments). There is a very good data structure that will solve this problem: NSCountedSet.

The counted set is unordered, but does care about the number of items present, so you don't end up with @[1, @1, @2] == @[@1, @2, @2].

NSArray *array1 = @[@1, @1, @2];
NSArray *array2 = @[@1, @2, @2];

NSCountedSet *set1 = [[NSCountedSet alloc] initWithArray:array1];
NSCountedSet *set2 = [[NSCountedSet alloc] initWithArray:array2];

BOOL isEqual = [set1 isEqualToSet:set2];
NSLog(@"isEqual:%d", isEqual);

Solution 3

Try this. What I am doing is make a copy of your first array & remove copy elements from the second array. If its empty then its equal, else not equal.

This has lesser memory foot print than @rmaddy solution. You create a duplicate of only one array not both arrays...

NSMutableArray *copyArray;
if([arr1 count] >= [arr2 count])
{
    copyArray = [NSMutableArray arrayWithArray:arr1];
    [copyArray removeObjectsInArray:arr2];
}
else //c(arr2) > c(arr1)
{
    copyArray = [NSMutableArray arrayWithArray:arr2];
    [copyArray removeObjectsInArray:arr1];
}

if([copyArray count] != 0)
    NSLog('Not Equal');
else
    NSLog('Equal');

UPDATE1: If you want to use arr2 after this then its been changed. You need to make a copy of it, then in that case memory-wise its same as what rmaddy solution takes. But still this solution is superior since, NSSet creation time is far more than NSArray - source.

UPDATE2: Updated to make the answer more comprehensive incase one array is bigger than other.

Solution 4

Just like rmaddy said, those NSArrays are not equal. Try this:

-(BOOL)compareArrayIgnoreIndexes:(NSArray*)arrayOne toArray:(NSArray*)arrayTwo{
    NSSet *setOne=[[NSSet alloc]initWithArray:arrayOne];
    NSSet *setTwo=[[NSSet alloc]initWithArray:arrayTwo];
    return [setOne isEqualToSet:setTwo];
}

Solution 5

I found the solution,,we can achieve that by sorting the array elements

 NSArray *arr1 = [[NSArray alloc]initWithObjects:@"a2223a",@"ab33b",@"a1acdf",@"ac23c45", nil];
    NSArray *arr11 =  [arr1 sortedArrayUsingSelector:@selector(localizedCompare:)];
    NSArray *arr2 = [[NSArray alloc]initWithObjects:@"ab33b",@"ac23c45",@"a1acdf",@"a2223a", nil];
    NSArray *arr22= [arr2 sortedArrayUsingSelector:@selector(localizedCompare:)];
    if([arr11 isEqualToArray:arr22])
    {
        NSLog(@"equal");
    }
    else
    {
        NSLog(@"Not equal");
    }
Share:
22,858
Ravi
Author by

Ravi

Updated on January 13, 2022

Comments

  • Ravi
    Ravi over 2 years

    I have two NSArrays where the objects of the arrays are the same but might be in different indices. It should print both are equal irrespective of their indices.

    NSArray *arr1 = [[NSArray alloc]initWithObjects:@"aa", @"bb", @"1", @"cc", nil];
    NSArray *arr2 = [[NSArray alloc]initWithObjects:@"bb", @"cc", @"1", @"aa", nil];
    
    if ([arr1 isEqualToArray:arr2])
    {
        NSLog(@"Equal");
    }
    else
    {
        NSLog(@"Not equal");
    }
    

    The above code is printing 'Not equal' but it should print 'Equal'. How can I do this?

  • rmaddy
    rmaddy over 11 years
    removeObjectsInArray: has a void return type. That won't work as-is.
  • CodaFi
    CodaFi over 11 years
    Perhaps you meant to call -removeObjectsFromArray:, then take a -count compared to 0 (inventive, I like it).
  • rmaddy
    rmaddy over 11 years
    @CodaFi no more so than the other answers once you include the two original arrays.
  • CodaFi
    CodaFi over 11 years
    @rmaddy: He's performing two sorts on a total of three arrays. Tell me that's not inefficient?
  • rmaddy
    rmaddy over 11 years
    @CodaFi I see two sorts on two arrays.
  • CodaFi
    CodaFi over 11 years
    /*a total of three arrays*/, and I see no argument against the sorting. It's expensive in most cases (but I will admit that there is a temporary speed boost after an initial sort, but only if the same array is being sorted twice).
  • Martin R
    Martin R over 11 years
    This method wrongly reports arrays as equal if arr2 contains "more" elements than arr1, eg. arr1 = @[@1, @2], arr2 = @[@1, @2, @3]. - And why do think that arr2 is modified by this method?
  • Martin R
    Martin R over 11 years
    Remark: This method ignores duplicates, e.g. @[@1, @2] and @[@1, @1, @2, @2] are considered equal. But it is not obvious from the question if this is the desired behaviour or not.
  • Srikar Appalaraju
    Srikar Appalaraju over 11 years
    @MartinR updated my answer to handle the scenario you correctly pointed out. Also since removeObjectsInArray modifies the array inplace, I had mentioned it for the sake of completeness...
  • Martin R
    Martin R over 11 years
    Still does not work (sorry :-). Try arr1 = @[@1, @1, @1] and arr2 = @[@1, @2]. - And removeObjectsInArray modifies only the receiver copyArray, not the argument arr1 or arr2.
  • rmaddy
    rmaddy over 11 years
    @CodaFi Where is this "three" coming from? There are two original arrays. There are two more sorted arrays. That's a total of four arrays. The code in the answer has four arrays. Why do you keep saying "three"?
  • Martin R
    Martin R over 11 years
    This solution is identical to Srikar's solution posted earlier. And it does not work reliably for the same reasons, see my comments above.
  • OC Rickard
    OC Rickard over 10 years
    You could fix Martin R's question fairly easily, but What about @[@1, @1, @2], and @[@1, @2, @2]?
  • voromax
    voromax over 10 years
    Unfortunately this class does not fit the [ios] tag
  • Unheilig
    Unheilig over 10 years
    @rmaddy Am a bit late here, but wanted to ask: did you eventually manage to spot the 3rd one here? Thanks.
  • rmaddy
    rmaddy over 10 years
    @Unheilig No and after looking at this again I still have no idea what CodaFi was referring to.
  • Unheilig
    Unheilig over 10 years
    @CodaFi Hi CodaFi. Just happened to see this post and out of curiosity I tried looking at the answer here to find the hidden gem you mentioned - the 3rd sorted array. Unfortunately I have not been able to spot it. I have even tried looking at it with my eye crossed - that didn't work either. So, could you please tell me why there are 3 sorted arrays here when there are only two arrays being sorted? Thanks in advance.
  • OC Rickard
    OC Rickard over 10 years
    Sorry, why? NSCountedSet has been available in iOS since 2.0: developer.apple.com/library/ios/documentation/cocoa/referenc‌​e/…
  • OC Rickard
    OC Rickard over 10 years
    Just realized my original answer referenced the mac docs, so sorry for the confusion. The class is available for iOS too -- updated answer to correct the link.
  • Unheilig
    Unheilig over 10 years
    @MartinR I am late here. I happened to come across this post yesterday. Was hoping to ask if you could provide me a little clarification from Ravi's answer below where CodaFi says that are 3 arrays being sorted when actually 2 are actually sorted. I have looked at it for many hours, I can't spot the 3rd one. If you know what the 3rd array is, could you please tell me where it is? Thanks in advance.
  • Martin R
    Martin R over 10 years
    @Unheilig: Actually I don't know. But Ravi's solution has the disadvantage that the objects must be comparable (as strings), so it is not so general. Using a counted set (as in another answer below) seems better to me. (Which is incidentally the same as this answer stackoverflow.com/a/15710166/1059705, but I am sure that I was not the first one.)