合并NSMutableArray和NSArray,过滤重复项。

8
我有两个数组,一个是NSMutableArray,另一个是NSArray。NSMutableArray是仓库,它存储来自NSArrays源的结果。每5分钟,会出现一个新的NSArray,需要对数据进行过滤和排序。
按日期排序很容易,所以我成功地让NSArray通过NSDate排序了。不需要对另一个数组进行排序,因为这只会导致用户混乱。
我想做的是:NSArray拥有许多不同的对象,它们都响应-[object name],返回NSString。该NSArray需要合并到NSMutableArray中,仅添加新对象。
合并本身没有问题,但性能方面需要考虑。NSMutableArray最多可以包含3000个项目,而NSArray最多可以包含250个项目,尽管通常只有其中5或6个需要合并到NSMutableArray中。
那么,我的问题是:如何在Objective-C中合并两个数组,过滤重复项,而不必迭代(250*3000)次?
汤姆
编辑以澄清一些事情 “重复”对象是对用户而言重复的对象,但对代码却不是。它们具有相同的名称,但地址不同。
更多澄清:@“value”!= @“value” // true
6个回答

10

你要确定被存储在数组中的对象中是否有name属性。如果是这样,可以使用相对简单的NSPredicate在将结果添加到可变数组之前筛选不可变数组。以下是一个示例:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NONE name == %@.name", mutableArray];
resultsArray = [immutableArray filteredArrayUsingPredicate:predicate];
[mutableArray addObjectsFromArray:immutableArray];

这个解决方案看起来不错,但可能只比手动迭代所有对象的性能消耗略微少一些。我目前将其用作临时解决方案,直到我实现更好的方法。 - Tom van der Woerdt
3
由于某种不明原因,它会引发一个异常(iOS7):'ALL或ANY运算符的左侧必须是NSArray或NSSet。' 当将谓词字符串的顺序反转时,它可以正常工作:“NONE %@.name == name”。 - Emmanuel Paris

6
这个怎么样:
[mutable removeObjectsInArray:newArray];
[mutable addObjectsFromArray:newArray];

它可能不是最胖的,但很容易实现 :)


仅当实际对象相同时才有效。这里不起作用,因为需要一个属性相同才能有一个副本。 - meaning-matters

0

你可以使用 NSSetNSMutableSet 代替吗?这可以帮助解决重复问题。

编辑:

根据您的评论,您可以使用 NSSet 快速检查对象成员资格,除了您的数组。它需要更多的内存,但如果您不介意,它可以让您快速检查。您将拥有您的 NSMutableArray 后备存储器,然后是一个 NSSet 来跟踪对象成员资格。您将保持不变的是 NSMutableArray 不包含重复项。您可以使用以下代码:

// Assume that arrayStore is an NSMutableArray * instance variable
// Also, storeSet is an NSMutableSet * ivar

- (void)addObjectsFromArray:(NSArray *)data
{
    for (id item in data) {
        if (![storeSet member:item]) {
            // Will have to keep arrayStore sorted somehow
            [arrayStore addObject:item];
            [storeSet addObject:item];
        }
    }
}

你只需要遍历 NSArray。我不确定 NSSet 是如何实现的,但是检查成员资格不会像对未排序的数组一样是 O(n) 操作。

这不是最有效的方法,但它可以很好地与你已经有的东西配合使用,只需进行小的修改即可。


NSSet有两个特点:1)无序;2)只能重复添加相同的对象。两个不同地址但内容相同的对象将不被NSSet识别。 - Tom van der Woerdt
1
@Tom van der Woerdt:集合使用isEqual来比较对象,因此如果您的类重写了isEqual,则可以基于其他内容进行比较而不是内存位置。另外,集合是无序的,但是您可以在需要时将集合转换为数组并对其进行排序(除非您需要始终排序)。 - mipadi
哦,我不知道isEqual这部分,听起来不错。然而,是的,它们必须始终排序。 - Tom van der Woerdt

0

可能有很多方法可以显著提高性能,但要能够建议任何一种方法,我们真的需要更多地了解数组中的对象:“它们”是什么?它们如何被使用?(例如,存储数组中的项目是否在表视图中显示?)

NSMutableDictionaryNSMutableSet等可以与NSMutableArray结合使用,以有效地组织和实现模型。

例如,假设我们知道该对象代表一个人:MDPerson。一个人有性别、出生日期、姓名、唯一标识和一组可变属性。有了这个更高层次的理解,我们知道只有当两个人的唯一标识相同时它们才相等(换句话说,两个不同的人可以有相同的姓名、性别和出生日期)。假设您的主要NSMutableArray由3000个人的列表组成。传入的数组由500个已经在主NSMutableArray中的人组成。这500个人中的一些实例可能具有“更新”的属性,这意味着它们在主数组中的实例需要更新这些信息。

考虑到这一点,很明显主列表应该实现为NSMutableDictionary而不是NSMutableArray。在字典中,人的唯一ID将成为键,他们的人员实例将成为键的值。然后,您只需要一次循环遍历传入的500个人的数组:

 // main dictionary is called personIDsAndPersons

 for (MDPerson *person in incomingPersons) {
      MDPerson *existingPerson = [personIDsAndPersons objectForKey:[person uniqueID]];
      // if nil, the person doesn't exist
      if (existingPerson) {
          // update the existing person's attributes
          [existingPerson setUniqueAttributes:[person uniqueAttributes]];
      }
 }

再次强调,如果不了解更多细节或没有更高层次的理解对象是什么,我们就只是在瞎猜。

您提到只有名称相同的两个项目才相同。那么,主数组中的每个项目都有唯一的名称吗?如果是这样,您可以使用NSMutableDictionary以有效的方式访问对象,通过将字典中的键设置为名称,将值设置为对象实例。然后,您可以使用单独的NSMutableArray仅用于显示目的:它允许对存储在NSMutableDictionary中的相同对象进行有序、排序的组织。请记住,当您将对象添加到数组或字典中时,通常不会创建新副本,而是保留现有对象。


所有项目都是不可变对象,都是从一个“item”类继承而来的子类,该类要求所有子类实现一个“name”方法以允许检查重复项。是的,它们都在某种表格视图中。 - Tom van der Woerdt

0

编辑以删除一些愚蠢的内容(但仍有很多)

有几个选项:

  1. 使用 removeObjectIdenticalTo 从 NSMutableArray 中删除所有匹配的对象。这需要遍历较小的数组,但正如您所指出的,它们通常很小。然后,

  2. 使用 addObjectsFromArray 添加新数组中的所有项目

或者...实际上,更快的方法可能是:

  1. 遍历新数组,使用 indexOfObjectIdenticalTo 查找匹配项,并使用 addObject 添加非匹配对象。

无论哪种方式都很耗费时间,但可行。


这不符合我的需求:对象不是完全相同的,只有-[object name] 的值相同。 - Tom van der Woerdt

0
我会先创建一个新的可变数组,其中包含您的NSMutableArray和NSArray的内容。然后,根据名称属性对新数组进行排序,然后只运行一次数组,仅提取唯一项。

我认为这会稍微减少所需的计算量,但NSMutableArray应该保持不变,只添加新对象。 - Tom van der Woerdt
实际上,计算量的减少将相当惊人。从3000 * 250 = 750,000个计算,您将转向约40,000个...这几乎是两个数量级的改进。谓词方法更加简洁,但我怀疑它不会更快。如果您编写自己的排序算法,每当比较两个等效项时就可以将一个项从考虑中删除,那么您可能可以稍微改进一下。 - ericg

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