25

目标是比较两个数组并检查它们是否包含相同的对象(尽可能快 - 数组中有很多对象)。无法检查数组,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;
}

这可行,但这是两个嵌套的快速枚举。有没有办法进行更快的比较?

4

10 回答 10

43

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

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

前任:

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");
}
于 2013-02-18T11:45:57.577 回答
13

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

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

比较两者使用

if([set1 isEqualToSet:set2]) {

}
于 2013-02-18T11:36:31.537 回答
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;
}
于 2013-02-18T11:45:11.200 回答
3

试图让接受的答案起作用,但它并不是最适合我的情况。

我找到了这个答案,所有的功劳都归功于该方法的@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 帮助我提高效率

于 2014-10-30T04:51:47.203 回答
2

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

于 2014-03-12T17:11:48.730 回答
1

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

于 2013-02-18T11:36:28.963 回答
1
[docTypes containsObject:@"Object"];

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

于 2013-02-18T11:39:55.063 回答
1
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! */
}
于 2013-02-18T16:36:04.630 回答
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]" .. 这显然是错误的..

于 2015-05-15T11:01:37.207 回答
-5

我想这会做:

[array1 isEqualToArray:array2];

返回布尔值;

于 2013-02-18T11:33:26.940 回答