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

Ios 检查一个数组是否包含与另一个数组相同的对象的最快方法,ios,objective-c,nsarray,fast-enumeration,Ios,Objective C,Nsarray,Fast Enumeration,我们的目标是比较两个数组,并检查它们是否包含相同的对象(尽可能快-数组中有很多对象)。无法使用isEqual:检查数组,因为它们的排序不同 我已经尝试了这里发布的解决方案(参见Peter Hosey文章的最后一段代码)。但这不适用于排序不同的数组 我现在使用的代码如下: + (BOOL)arraysContainSameObjects:(NSArray *)array1 andOtherArray:(NSArray *)array2 { // quit if array count is

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

我已经尝试了这里发布的解决方案(参见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;
}
这是可行的,但这是两个嵌套的快速枚举。有没有办法进行更快的比较?

我想这样可以:

[array1 isEqualToArray:array2];

返回布尔

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

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

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

if([set1 isEqualToSet:set2]) {

}

它将为您的需求工作。fast将尽早为其返回布尔值。

使用containsObject:method,而不是迭代整个数组

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

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

最快的方法是对两个数组进行排序并进行比较

例:

主要的优点是,您可以将其用于任何类型的对象:自定义、系统、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! */
}

如果要检查两个数组是否包含相同的副本,只需使用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%的时间数组1的随机元素不在数组2中?数组经常被排序吗?在这种情况下,您可以检查是否有相同位置的相同对象,然后只考虑那些不相同的对象。如果一个数组包含对象a、b、c、d、e,而另一个数组包含对象a、b、x、d、y,则只需比较数组[c、e]与[x、y]

试图让被接受的答案起作用,但它并不完全适合我的情况

我找到了,所有的功劳都归于@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帮助我提高it效率

我知道已经晚了,但我只想分享我所做的

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]”。。这显然是错误的。

您还需要验证它是否具有相同数量的匹配对象吗?例如,如果数组1有2个X实例,但数组2只有1个,那么它失败了?是的,这也应该得到验证。在这种情况下,您别无选择,只能对它们进行排序并比较。这是否有帮助:-
-(unsigned)numberOfDistinctObjects{return[[NSSet setWithArray:self]count];}
好的,比较将是O(n),再加上排序算法的效率。NSArray类参考中对
isEqualToArray:
:“如果两个数组中的对象数量相同,且每个数组中给定索引处的对象都满足isEqual:测试,则两个数组的内容相等。”-由于数组的排序不同,我认为即使两个数组中的对象相同但排序不同,该方法也会返回NO。我也考虑了这种方式,但是如果我的评论条件有效,它就不起作用了。你比@borrden:)领先了一步。如果你不关心数组中同一对象的多个实例,这是正确的答案。我想我必须对两个数组进行排序?如果第一个数组未排序,而另一个数组已排序,我猜如果包含相同的对象,
isEqualToArray
不会返回YES?(编辑:刚刚看到博尔登在第一篇文章中添加了这个评论;))对不起,我以为这篇文章已经整理好了,正在修复。哦,是的,我刚刚注意到。。。类似的想法。@AKV Hmmm我分析过,后来了解到,这是最好的方法,其他方法也需要同样的时间@FrankZp:您也可以这样检查,但不建议使用vague.NSMutableArray*a1=[NSMutableArray arrayWithArray:array1];NSMUTABLEARRY*a2=[NSMUTABLEARRY arrayWithArray:array2];[a2 removeObjectsInArray:a1];if([a2 count]){NSLog(@“两者相同”);}else{NSLog(@“两者不同”);}@AKV:感谢您的评论-但我认为我正在使用排序并与
isEqualToArray:
进行比较,因为这非常好。
containsObject
的复杂性在最坏的情况下通常是线性的(即使对数组进行了排序),因此这并不是渐进地比两个嵌套的快速枚举更有效。@DanielMartín Hmmm我同意。正如Borrden正确地说的,唯一的选择是排序和比较。但是,如果数组很可能不相等,这种方法可能更快退出。
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]);
}
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");
}
NSString *stringArr1 = [NSString stringWithFormat:@"%@", array1];
NSString *stringArr2 = [NSString stringWithFormat:@"%@", array2];

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