【问题标题】:Merge NSMutableArray with a NSArray, filtering the duplicates将 NSMutableArray 与 NSArray 合并,过滤重复项
【发布时间】:2011-05-26 04:38:09
【问题描述】:

我有两个数组,一个 NSMutableArray 和一个 NSArray。 NSMutableArray 是“存储”,它存储来自 NSArrays 源的结果。每 5 分钟,一个新的 NSArray 进来,需要对数据进行过滤和排序。

按日期排序非常简单,所以我设法让 NSArray 按 NSDate 排序。不需要对另一个数组进行排序,因为它只会引起用户的混淆。

我想要做的:NSArray 有很多不同的对象,它们都响应 -[object name],返回一个 NSString。 NSArray 需要合并到 NSMutableArray,只添加new 个对象。

合并本身没有问题,但性能是。 NSMutableArray 最多可以包含 3000 个项目,而 NSArray 最多可以包含 250 个项目,尽管通常只有其中的 5 或 6 个必须合并到 NSMutableArray 中。

所以,我的问题是:如何在 Objective-C 中合并两个数组,过滤重复项,而不重复 (250*3000) 次?

汤姆

编辑以澄清一些事情
“重复”对象是对用户重复但对代码不重复的对象。它们具有相同的名称,但不同的地址相同。

更多说明:@"value" != @"value" // true

【问题讨论】:

    标签: objective-c


    【解决方案1】:

    name 是存储在数组中的对象的属性吗?如果是这样,您可以使用一个相当简单的 NSPredicate 来过滤不可变数组,然后再将结果添加到可变数组。这是一个例子:

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

    【讨论】:

    • 这个解决方案看起来不错,但与简单地手动迭代所有对象相比,它可能只消耗一点性能。我目前将此用作临时解决方案,直到我实施了更好的方法。
    • 由于一个模糊的原因,它引发了一个异常(iOS7):'ALL 或 ANY 运算符的左侧必须是 NSArray 或 NSSet。颠倒谓词字符串的顺序时工作正常:@"NONE %@.name == name"
    【解决方案2】:

    这个怎么样:

    [mutable removeObjectsInArray:newArray];
    [mutable addObjectsFromArray:newArray];
    

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

    【讨论】:

    • 仅在实际对象相同时才有效。在这里不起作用,因为属性必须相同才能有重复。
    【解决方案3】:

    进行了编辑以消除一些愚蠢(尽管留下了很多)

    几个选项:

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

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

    或者......好吧,实际上它可能会更快:

    1. 遍历新数组以查找与indexOfObjectIdenticalTo 匹配的对象,使用addObject 添加不匹配的对象。

    无论哪种方式都很昂贵,但可行。

    【讨论】:

    • 这不能满足我的需要:对象不相同,只有 -[object name] 的值是
    【解决方案4】:

    我可能会首先创建一个新的可变数组,其中包含 NSMutableArray 和 NSArray 的内容。然后,根据 name 属性对新数组进行排序,然后遍历数组一次,只提取唯一项。

    【讨论】:

    • 我认为它会稍微(!)减少所需的计算量,是的,但是 NSMutableArray 应该保持不变并且只添加新对象。
    • 实际上,计算次数的减少会相当显着。从 3000 * 250 = 750,000 次计算,您将达到 ~ 40,000....这几乎是两个数量级的改进。谓词方法更干净,但我怀疑它会快得多。如果您编写自己的排序算法,当比较两个相等的项目时,可以将项目排除在考虑范围之外,您可能会有所改进。
    【解决方案5】:

    你能改用NSSetNSMutableSet 吗?这可能有助于处理重复问题。

    编辑:

    根据您的 cmets,除了您的数组之外,您还可以使用 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:集合使用isEqual 来比较对象,因此如果您的类覆盖isEqual,您可以根据内存位置以外的其他内容进行比较。此外,集合是无序的,但您可以将集合转换为数组并在需要时对其进行排序(除非您需要一直对其进行排序)。
    • 哦,我不知道isEqual 部分,听起来不错。但是,是的,它们必须一直进行排序。
    【解决方案6】:

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

    NSMutableDictionaryNSMutableSet等可以与NSMutableArray结合,以高效的方式组织和实现模型。

    例如,假设我们知道对象代表一个人:MDPerson。一个人有一个性别、一个出生日期、一个名字、一个唯一的 id 和一组可以改变的属性。鉴于对对象代表的这种更高层次的理解,我们知道只有当他们的唯一 ID 相同时,两个人是平等的(换句话说,两个不同的人可以有相同的姓名、性别和出生日期)。假设您的主要 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]];
          }
     }
    

    同样,在不了解更多细节或对物体是什么有更高层次的了解的情况下,我们实际上只是在黑暗中拍摄。

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

    【讨论】:

    • 所有项目都是不可变对象,都是从一个“项目”类继承而来的,该类要求所有子类实现“名称”方法以允许检查重复项。是的,它们都在某种表格视图中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-18
    • 1970-01-01
    • 2014-07-10
    • 2011-11-07
    相关资源
    最近更新 更多