在Objective-C中比较数组

14

好的,一个非常简单的问题...在C++中似乎可以工作,但在Objective-C中我似乎遇到了一些困难:S... 如果你想比较两个数组,应该像这样:

for ( int i = 0; i < [appdelegate.nicearray count]; i++ ) 
{ 
  if ( appdelegate.nicearray[i] == appdelegate.exercarray[i] )
  { 
     NSLog(@"the same elements in this selection");
  }
}

问题具体是什么?

5个回答

44
这些是Cocoa数组对象(NSArray的实例),而不是C数组或C++向量,并且请记住Objective-C没有操作符重载。您可以使用对象的唯一功能是将其传递,存储在变量中并向其发送消息。

所以,在Objective-C对象中,数组下标运算符是错误的。我认为对Objective-C对象解除引用指针甚至在语言上也是无效的,因此这段代码应该会给你编译器错误。虽然我可能记错了。如果它确实到达运行时,那么这段代码迟早会崩溃,因为您正在访问超出数组对象末尾的内存。

(2013年的编辑:Objective-C现在支持对象下标。这最终转换为相应的objectAtIndex:replaceObjectAtIndex:withObject:消息。因此,问题中的代码现在实际上可以工作,尽管这仍不是简单遍历数组,更不用说比较两个数组的正确方法。)

从NSArray对象中按索引检索对象的正确方法不是使用数组下标运算符,而是向数组对象发送objectAtIndex:消息:
[myArray objectAtIndex:i]

如果您不需要对数组对象执行其他操作(如替换可变数组中的对象),则迭代数组元素的正确方法是直接循环遍历它(这称为“快速枚举”):

for (MyObject *myObject in myArray) {
    …
}

NSArray同样响应objectEnumeratorreverseObjectEnumerator,它们返回一个类似可迭代的对象。这两者中,reverseObjectEnumerator在新代码中更为有用,因为你可以直接迭代数组以正向迭代。在快速枚举存在之前,这两种方式都非常有用;代码看起来像这样:

NSEnumerator *myArrayEnum = [myArray objectEnumerator];
MyObject *myObject;
while ((myObject = [myArrayEnum nextObject])) {
    …
}

(是的,那是在条件语句中的赋值。故意这样做,因此多了一个()。我们当时写代码很大胆,不是吗?)

不过,对于你正在做的事情,你更可能想要向其中一个数组发送 isEqualToArray: 消息,就像 Williham Totland 建议的那样:

BOOL theyAreEqual = [myFirstArray isEqualToArray:mySecondArray];

首先确保两个数组具有相同的长度,然后同时遍历它们,对每一对对象发送isEqual:消息。如果每个isEqual:消息都返回YES,它将返回YES;否则返回NO。数组可能包含不同的对象,但只要每一对相等,数组本身就是相等的。

这假设您想进行对象相等性比较。如果两个独立的对象相等,则当您向其中一个对象发送isEqual:消息并传递另一个对象时,其中一个对象会响应并返回YES。如果您想比较对象的标识,则需要自己进行锁步循环,并使用==运算符。

BOOL arraysContainTheSameObjects = YES;
NSEnumerator *otherEnum = [otherArray objectEnumerator];
for (MyObject *myObject in myArray) {
    if (myObject != [otherEnum nextObject]) {
        //We have found a pair of two different objects.
        arraysContainTheSameObjects = NO;
        break;
    }
}

但这很不可能发生。大多数情况下,我想要测试对象的相等性而不是身份,所以isEqualToArray:就是我想要的。


随机跟进问题:[nsArrrayInstance isEqual:otherInstance] 是否等同于 [nsArrrayInstance isEqualToArray:otherInstance] - nmr
1
@nmr:几乎正确。有两个特殊情况的差异:http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/FrameworkImpl.html#//apple_ref/doc/uid/20001286-1007347、http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974-CH4-SW61 - Peter Hosey
简而言之,第一个链接指出 isEqualTo... 可能会假定参数是正确的类型~ 我不确定第二个链接讨论的是哪种边缘情况。也许我可以麻烦您详细说明一下? - nmr
2
@nmr:“在Cocoa框架的所有isEqualTo<Type>:方法中,nil不是有效的参数,这些方法的实现在接收到nil时可能会引发异常。然而,为了向后兼容,Cocoa框架的isEqual:方法确实接受nil,并返回NO。” - Peter Hosey
@Peter Hosey 太棒了,谢谢。你认为这一切的必然结果是,如果你实现了 isEqualTo<Type>:,那么不实现isEqual:就会很奇怪?并且给定<Type>类型的参数,它们应该返回相同的值? - nmr
@PeterHosey:我知道这是一个旧的线程,但也许你可以更新你的答案,因为现在Objective-C中已经有下标运算符了。 - Losiowaty

26
您需要使用isEqualToArray:方法,示例代码如下:
if ([arrayOne isEqualToArray:arrayTwo]) {
  // Do something
}

这将递归比较两个数组,同时具有不需要无谓的迂回和不需要循环的优点。


1
这是我根据排名靠前的示例编写的小程序。它仅检查数组是否包含相同的值,而不考虑顺序和重复项。我主要用它来比较两个字典的键(它们通常以各种排序顺序返回其所有键数组),以查看它们是否包含相同的对象。感谢Peter Hosley提供的我所改编的示例。
#pragma mark - Arrays
// Check to see if arrays contain the same elements, not necessarily in the same order
// This is different from [array isEqualToArray:responseKeys] which demands the same order in both arrays
// ## Does not compensate for duplicate entries in an array
+ (BOOL)doArraysContainTheSameObjects:(NSArray *)firstArray withArray:(NSArray *)secondArray {
    BOOL arraysContainTheSameObjects = YES;

    for (id myObject in firstArray) {
        if (![secondArray containsObject:myObject]) {
            // We have found an object that is not in the other array.
            arraysContainTheSameObjects = NO;
            break;
        }
    }
    return arraysContainTheSameObjects;
}

老实说,如果要成为通用目的,我们还应该检查第一个数组是否包含第二个数组中的所有对象。 - Alex Zavatone
如果第一个数组为nil且第二个数组为空数组,则上述方法将返回true。 - IronMan

1

试试告诉我们当你运行这段代码时得到的结果。方法是正确的,但试试这个:

for (int i =0; i< appdelegate.nicearray.count; i++)
{
    if ([[appdelegate objectAtIndex:i] isEqual: [appdelegate.exercarray objectAtIndex:i]])
    {
        NSLog(@"the same");
    }
}  

通常情况下,你应该使用isEqual:来比较对象,而不是指针相等性。 - Chuck
此外,你可以只使用 isEqualToArray: 来完成这个任务,正如 Williham Totland 建议的那样。(不过他指出应该使用 objectAtIndex: 而不是数组下标操作符也是值得赞扬的。) - Peter Hosey

0

在比较数组时,我会执行以下操作:

  • 检查其中一个数组是否为nil,而另一个不是
  • 检查长度是否相同
  • 迭代(使用类似于for循环的方式)每个元素,检查另一个数组中匹配的元素。

要比较元素,您需要定义您认为“相等”的内容。如果数组中的指针相等,则它们是否相等,或者如果内容相等,则它们是否相等。

对于指针情况,您可以使用==。

对于深度比较,您可能需要使用CompareTo或类似的东西。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接