检查数组是否包含另一个数组的相同对象的最快方法

时间:2013-02-18 11:28:50

标签: ios objective-c nsarray fast-enumeration

目标是比较两个数组并检查它们是否包含相同的对象(尽可能快 - 数组中有很多对象)。无法使用isEqual:检查数组,因为它们的排序方式不同。

我已经尝试过此处发布的解决方案(https://stackoverflow.com/a/1138417 - 请参阅Peter Hosey发布的帖子的最后一个代码段)。但这不适用于不同排序的数组。

我现在使用的代码如下:

+ (BOOL)arraysContainSameObjects:(NSArray *)array1 andOtherArray:(NSArray *)array2 {
    // quit if array count is different
    if ([array1 count] != [array2 count]) return NO;

    BOOL bothArraysContainTheSameObjects = YES;
    for (id objectInArray1 in array1) {
        BOOL objectFoundInArray2 = NO;
        for (id objectInArray2 in array2) {
            if ([objectInArray1 isEqual:objectInArray2]) {
                objectFoundInArray2 = YES;
                break;
            }
        }
        if (!objectFoundInArray2) {
            bothArraysContainTheSameObjects = NO;
            break;
        }
    }

    return bothArraysContainTheSameObjects;
}

这有效,但这些是两个嵌套的快速枚举。有没有办法做更快的比较?

10 个答案:

答案 0 :(得分:41)

根据你的代码,你对相同数量的元素是严格的,第一个数组的每个对象应该在第二个数组中,反之亦然。

最快的方法是对数组进行排序并比较它们。

例如:

NSArray *array1=@[@"a",@"b",@"c"];
NSArray *array2=@[@"c",@"b",@"a"];

array1=[array1 sortedArrayUsingSelector:@selector(compare:)];
array2=[array2 sortedArrayUsingSelector:@selector(compare:)];

if ([array1 isEqualToArray:array2]) {
    NSLog(@"both have same elements");
}
else{
    NSLog(@"both having different elements");
}

答案 1 :(得分:12)

如何将两个数组转换为集合并进行比较。

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

使用

比较两者
if([set1 isEqualToSet:set2]) {

}

答案 2 :(得分:3)

使用containsObject:方法而不是迭代整个数组。

NSArray *array;
array = [NSArray arrayWithObjects: @"Nicola", @"Margherita",                                       @"Luciano", @"Silvia", nil];
if ([array containsObject: @"Nicola"]) // YES
  {
    // Do something
  }
像这样

+ (BOOL)arraysContainSameObjects:(NSArray *)array1 andOtherArray:(NSArray *)array2 {
    // quit if array count is different
    if ([array1 count] != [array2 count]) return NO;

    BOOL bothArraysContainTheSameObjects = YES;

    for (id objectInArray1 in array1) {

        if (![array2 containsObject:objectInArray1])
        {
            bothArraysContainTheSameObjects = NO;
            break;
        }

    }

    return bothArraysContainTheSameObjects;
}

答案 3 :(得分:3)

试图让接受的答案有效,但它并不适合我的情况。

我找到了this answer,所有信用都归功于@joel kravets的方法。

基本上使用比较器进行排序使您可以更轻松地使用对象进行排序 - 因此我在尝试使用上述解决方案时遇到了问题。

NSArray * array1 = [NSArray arrayWithArray:users];
NSArray * array2 = [NSArray arrayWithArray:threadUsers];

id mySort = ^(BUser * user1, BUser * user2){
    return [user1.name compare:user2.name];
};

array1 = [array1 sortedArrayUsingComparator:mySort];
array2 = [array2 sortedArrayUsingComparator:mySort];

if ([array1 isEqualToArray:array2]) {
    NSLog(@"both are same");
}
else{
    NSLog(@"both are different");
}

以前我曾尝试使用上面的其他答案,使用break来完成循环但最后这个答案最简单可能是由于它的速度而且最后我们有if语句允许我们放代码取决于它们是相同还是不同。

感谢Anoop让我走上正轨,Joel帮助我提高了效率

答案 4 :(得分:1)

这种方式的复杂性是O(N ^ 2),如果你遵循这种方法,你就不能以较低的复杂度来做。相反,如果你对两个数组进行排序然后比较它们,你可以用O(N log(N))来做。这样,在对它们进行排序后,您将使用isEqualToArray执行此操作:在其他N个操作中。

答案 5 :(得分:1)

[docTypes containsObject:@"Object"];

它适用于您的需求。早在快,它就会返回它的布尔值。

答案 6 :(得分:1)

NSArray *filtered = [someArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"someParamter == %@", paramValue]]];
if (filtered.count) {

}

主要的优点是你可以将它用于任何类型的对象:custom,system,NSDictionary。例如,我需要知道的是我的UINavigationController的堆栈是否包含MySearchResultsVC和MyTopMenuItemsVC:

    NSArray *filtered = [self.navigationController.viewControllers filteredArrayUsingPredicate:
                                     [NSPredicate predicateWithFormat:@"class IN %@",
                                      [NSArray arrayWithObjects:
                                       [MySearchResultsVC class],
                                       [MyTopMenuItemsVC class],
                                       nil]]];
if (filtered) {
/* ok, now we can handle it! */
}

答案 7 :(得分:1)

如果要检查两个数组是否包含相同的重复项,只需使用NSCountedSet。它就像一个NSSet,但是集合中的每个对象都有一个计数器,告诉你它多久被添加一次。所以

BOOL same = (array1.count == array2.count);
if (same && array.count > 0)
{
    NSCountedSet* set1 = [[NSCountedSet alloc] initWithArray:array1];
    NSCountedSet* set2 = [[NSCountedSet alloc] initWithArray:array2];
    same = ([set1 isEqual: set2]);
}

无论您如何操作,这都会非常耗时,因此您可以考虑是否有特殊情况可以更快地处理。这些数组通常是相同的,还是几乎相同的,或者99%的时间是不同的,并且99%的时间是array1的随机元素不在array2中?阵列经常排序吗?在这种情况下,您可以检查相同位置是否存在相同的对象,然后仅考虑那些不相同的对象。如果一个数组包含对象a,b,c,d,e而另一个包含a,b,x,d,y,则只需要比较数组[c,e]与[x,y]。

答案 8 :(得分:0)

我知道现在已经很晚了但我只想分享我的所作所为......

NSString *stringArr1 = [NSString stringWithFormat:@"%@", array1];
NSString *stringArr2 = [NSString stringWithFormat:@"%@", array2];

if ([stringArr1 isEqual: stringArr2])
    NSLog(@"identical");
else
    NSLog(@"not");

这就像比较“@ [@ 1,@ 2,@ 3,@ 4]”==“[@ 3,@ 2,@ 1,@ 4]” ..这显然是假的..

答案 9 :(得分:-4)

我想这会做:

[array1 isEqualToArray:array2];

返回bool;