代码之家  ›  专栏  ›  技术社区  ›  FrankZp

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

  •  24
  • FrankZp  · 技术社区  · 12 年前

    目标是将两个数组作为进行比较,并检查它们是否包含相同的对象(尽可能快——数组中有很多对象)。无法使用检查数组 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 回复  |  直到 8 年前
        1
  •  43
  •   Anoop Vaidya    9 年前

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

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

    前任:

    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");
    }
    
        2
  •  13
  •   Shashank    12 年前

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

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

    使用比较

    if([set1 isEqualToSet:set2]) {
    
    }
    
        3
  •  3
  •   Pushpak Narasimhan    12 年前

    使用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;
    }
    
        4
  •  3
  •   Community CDub    8 年前

    我试着让公认的答案发挥作用,但这并不是最适合我的情况。

    我找到了 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帮助我提高效率

        5
  •  2
  •   gnasher729    11 年前

    如果要检查两个数组是否包含相同的重复项,只需使用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]。

        6
  •  1
  •   Madhu    12 年前
    [docTypes containsObject:@"Object"];
    

    它将适用于您的需求。它会尽快返回布尔值。

        7
  •  1
  •   Ramy Al Zuhouri    12 年前

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

        8
  •  1
  •   iiFreeman    12 年前
    NSArray *filtered = [someArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"someParamter == %@", paramValue]]];
    if (filtered.count) {
    
    }
    

    主要优点是您可以将它用于任何类型的对象:自定义、系统、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! */
    }
    
        9
  •  0
  •   0yeoj    10 年前

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

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

        10
  •  -5
  •   spider1983    12 年前

    我想这样可以:

    [array1 isEqualToArray:array2];
    

    返回bool;

    推荐文章