检查两个 NSArray 是不是包含彼此的对象 (NSManagedObject)

Posted

技术标签:

【中文标题】检查两个 NSArray 是不是包含彼此的对象 (NSManagedObject)【英文标题】:Check two NSArrays for containing each other's objects (NSManagedObject)检查两个 NSArray 是否包含彼此的对象 (NSManagedObject) 【发布时间】:2012-02-14 16:12:11 【问题描述】:

我已经被以下问题困扰了很长一段时间了: 我有两个 NSArray,都包含 NSManagedObject 子类对象。 它们由不同的来源提供,但其中的对象仍然具有相同的属性/值。 我现在要做的是检查数组 A 是否包含数组 B 中的对象,反之亦然。 不幸的是,NSArray 的 containsObject 方法似乎在这里不起作用。 我认为它使用 id-testing 对每个对象进行相等性检查,不是吗?

那么,有人知道要尝试什么吗?

我什至尝试将我的对象封装在 NSSets 中,使用 member: 作为我的比较方法,但这也没有奏效,特别是因为 NSManagedObject 子类的“你不能覆盖”isEqual 等。

这是一个代码sn-p:

//manufacturers is an array, parsed out of some xml here...

for(Manufacturer *manu in [fetchedResultsController fetchedObjects])

    if(![manufacturers containsObject:manu])
    
        NSLog(@"Deleting %@", manu.name);
        [self.mContext deleteObject:manu];
    


for(Manufacturer *manu in manufacturers)

    if(![[fetchedResultsController fetchedObjects] containsObject:manu])
    
        NSLog(@"Adding %@", manu.name);
        [newArray addObject:manu];
    

提前感谢任何提示;)

【问题讨论】:

【参考方案1】:

我不确定这是否有效,但您可以尝试将您获得的字典与dictionaryWithValuesForKeys: 匹配。

类似这样的:

NSArray *keysToCompare = [NSArray arrayWithObjects:@"FooAttribute", @"BarAttribute", nil];

// create an array with the dictionary representation of the managedObject
NSMutableArray *fetchedObjectsDictionaries = [NSMutableArray arrayWithCapacity:[[fetchedResultsController fetchedObjects] count]];
for (NSManagedObject *object in [fetchedResultsController fetchedObjects]) 
    NSDictionary *dictionaryRepresentation = [object dictionaryWithValuesForKeys:keysToCompare];
    [fetchedObjectsDictionaries addObject:dictionaryRepresentation];


// another array with dictionaries for managedObjects
NSMutableArray *manufacturersDictionaries = [NSMutableArray arrayWithCapacity:[manufacturers count]];
for (NSManagedObject *object in manufacturers) 
    NSDictionary *dictionaryRepresentation = [object dictionaryWithValuesForKeys:keysToCompare];
    [manufacturersDictionaries addObject:dictionaryRepresentation];


// compare those dictionaries
for (NSInteger i = 0; i < [fetchedObjectsDictionaries count]; i++) 
    NSDictionary *dictionary = [fetchedObjectsDictionaries objectAtIndex:i];
    if (![manufacturersDictionaries containsObject:dictionary]) 
        // get the corresponding managedObject
        NSManagedObject *object = [[fetchedResultsController fetchedObjects] objectAtIndex:i];
        [newArray addObject:object];
    


如果这不起作用,您可以编写自己的 isEqualToManufacturer: 方法并手动枚举数组。

【讨论】:

如果这些数组包含多个对象,这将非常昂贵且缓慢。【参考方案2】:

您可以检查 3 种相等类型:相同的内存地址、托管对象 id 相等和值相等。您当前的代码已经检查对象是否共享相同的内存地址,这很可能不是您感兴趣的。这留下了两种可能的选择。使用托管对象 id 相等方法,您可以检查制造商是否指向数据库中的同一行。使用值相等,您可以根据共享值检查两个制造商是否相等。下面是一种检查 NSManagedObjectID 是否相等的方法。

for(Manufacturer *manu in [fetchedResultsController fetchedObjects])

    id databaseIDTest = ^(Manufacturer * checkManu, NSUInteger idx, BOOL *stop)
        return [[checkManu objectID] isEqual:[manu objectID]];
    ;

    if([manufacturers indexOfObjectPassingTest:databaseIDTest] == NSIndexNotFound)
    
        NSLog(@"Deleting %@", manu.name);
        [self.mContext deleteObject:manu];
    


for(Manufacturer *manu in manufacturers)

    id databaseIDTest = ^(Manufacturer * checkManu, NSUInteger idx, BOOL *stop)
        return [[checkManu objectID] isEqual:[manu objectID]];
    ;
    NSArray * fetchedObjects = [fetchedResultsController fetchedObjects];
    if([fetchedObjects indexOfObjectPassingTest:databaseIDTest] == NSIndexNotFound)
    
        NSLog(@"Adding %@", manu.name);
        [newArray addObject:manu];
    

【讨论】:

这并不完全正确。由于您处于相同的上下文中,因此比较两个指针(内存地址)和比较两个托管对象 ID 可以有效地做同样的事情,但比较两个指针要便宜 很多(数量级)。 非常感谢您的回答,但这似乎也不起作用......认为我可能不得不手动迭代我的数组并计算出现次数。至少这是我能想到的以“我的方式”测试对象的唯一方法。【参考方案3】:

您需要覆盖 -isEqual:,因为这是 -[NSArray containsObject:] 调用的内容:

- (BOOL)isEqual:(id)other;

    if (![other isKindOfClass:[Manufacturer class]]) 
        return NO;
    
    Manufacturer *otherManufacturer = other;
    return ([self.name isEqual:otherManufacturer.name] &&
           ...
           );

检查 NSSet 中的包含成本更低(如果遇到性能问题,这可能是有意义的)。它只有在你有一个相对不错的-hash 实现时才有效,但它很容易像这样实现:

- (NSUInteger)hash;

    return [self.name hash] + [self.foo hash] + ...;

不要对哈希处理太多麻烦,只需使用 2 - 3 个最有可能的值来唯一标识对象。

【讨论】:

我希望能够简单地覆盖我的对象的比较方法,但由于我使用的是 NSManagedObject 子类,所以我不能。否则这肯定是最好的解决方案;)

以上是关于检查两个 NSArray 是不是包含彼此的对象 (NSManagedObject)的主要内容,如果未能解决你的问题,请参考以下文章

使用基本Java检查两个字符串是不是是彼此的字谜[重复]

搜索字符串是不是包含来自 Nsdictionary 的 NSArray 的任何值

如何检查两个 SKSpriteNode 是不是彼此靠近?

如何在 iOS 中检查 NSArray 是不是为空或为空?

一种可能的算法来确定两个字符串是不是是彼此的字谜? [关闭]

检查两个数组是不是包含相同的对象 - 反应 componentDidUpdate [重复]