将对象添加到排序的 NSMutable 数组并回答索引路径

Posted

技术标签:

【中文标题】将对象添加到排序的 NSMutable 数组并回答索引路径【英文标题】:Add object to sorted NSMutable array and answer index path 【发布时间】:2012-03-26 05:00:06 【问题描述】:

我有一个名为 Topic 的类的排序可变数组。主题代表一组出版物。我在表格中显示主题,并定期从 Web 服务获取新出版物。当新的出版物到来时,我想用动画添加到表格中。

困扰我的是我需要做的计算工作才能添加到这个数组中,并回答正确的索引路径。有人可以提出比这更直接的方法吗:

// add a publication to the topic model.  if the publication has a new topic, answer
// the index path of the new topic
- (NSIndexPath *)addPublication:(Publication *)pub 

    // first a search to fit into an existing topic
    NSNumber *topicId = [pub valueForKey:@"topic_id"];
    for (Topic *topic in self.topics) 
        if ([topicId isEqualToNumber:[topic valueForKey:"id"]]) 
            // this publication is part of an existing topic, no new index path
            [topic addPublication:pub];
            return nil;
         
    

    // the publication must have a new topic, add a new topic (and therefore a new row)
    Topic *topic = [[Topic alloc] initWithPublication:publication];
    [self.topics addObject:topic];

    // sort it into position
    [self.topics sortUsingSelector:@selector(compareToTopic:)];

    // oh no, we want to return an index path, but where did it sort to?
    // yikes, another search!
    NSInteger row = [self.topics indexOfObject:topic];
    return [NSIndexPath indexPathForRow:row inSection:0];


// call this in a loop for all the publications I fetch from the server,
// collect the index paths for table animations
// so much computation, poor user's phone is going to melt!

我猜,第一次搜索是无法绕过的。但是有没有更有效的方法来向数组中添加新事物、维护排序并记住它的放置位置?

【问题讨论】:

【参考方案1】:

将值插入排序列表非常简单。例如,考虑如何将数字“3”插入到列表“1、2、7、9”中。你想做同样的事情。

使用for 循环按索引遍历数组。

对于每个对象,使用compareToTopic: 将其与要插入的对象进行比较。

当您找到要插入的适当索引时,使用-[NSArray insertObject:atIndex:] 将其插入。

然后返回带有该索引的NSIndexPath

编辑:而且,正如其他答案所指出的,二分搜索会更快——但要正确肯定更棘手。

【讨论】:

【参考方案2】:

这几乎肯定不是问题; NSArraysare actually hashes,搜索比真正的数组快得多。无论如何,您可能有多少主题?

不过,如果您测量性能并发现它很差,您可以考虑使用B-tree; Kurt Revis 在下面评论了一个指向 Core Foundation 中类似结构(binary heap)的链接:CFBinaryHeap。

另一个选项(也需要测量)可能是在您第一次遍历数组时进行比较;您可以标记该点并直接进行插入:

NSUInteger insertIndex = 0;
NSComparisonResult prevOrder = NSOrderedDescending;
for (Topic *topic in self.topics) 
    NSComparisonResult order = [topicId compareToTopic:topic];
    if (NSOrderedSame == order) 
        // this publication is part of an existing topic, no new index path
        [topic addPublication:pub];
        return nil;
    
    else if( prevOrder == NSOrderedDescending && 
             order == NSOrderedAscending )
    
        break;
    
    insertIndex++;
    prevOrder = order;

请注意,我没有对此进行测试,抱歉。

不过,我不确定这实际上是否比您编写的方式更好或更快。

不要担心计算机正在做的工作,除非它明显做得太慢。

【讨论】:

他担心的是,当他添加一个新对象时,他总是需要对数组进行排序。 @charith:我的观点是现有代码的性能实际上不太可能成为问题。我相信这是一个担心计算机正在做多少工作而没有真正看到它需要多少时间的情况。 CFBinaryHeap 可能是滚动自己的 B-tree 的好选择。 @Kurt:哦,男孩,我希望没有人认为我建议从头开始实施 B 树。感谢您的链接。 “不要担心计算机正在做的工作,除非它明显做得太慢了。”总体来说非常好的建议。凯撒万岁!【参考方案3】:

我猜你所做的是正确的。还有另一种方式。您可以编写自己的二进制搜索实现方法。 (其中只有几行代码)。您可以检索新对象应该适合的索引。并使用 insertObject:atIndex: 方法将新对象添加到所需的索引中。

【讨论】:

以上是关于将对象添加到排序的 NSMutable 数组并回答索引路径的主要内容,如果未能解决你的问题,请参考以下文章

过滤自定义对象的 NSMutable 数组

将 NSMutable 数组存储到 sqlite 数据库中

如何复制位于不同选项卡中的数组对象

如何将 NSMutable 数组中的数据存储在 Core Data 中?

如何在Vue中对对象数组进行排序和过滤

将嵌套的 JSON 对象展平并排序到 javascript 中的数组中