从NSArray中获取NSIndexSet

7

NSArray有一些有用的方法可以根据指定的索引查找对象。

// To find objects by indexes
- (id)objectAtIndex:(NSUInteger)index
- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes

// To find index by object
- (NSUInteger)indexOfObject:(id)anObject

然而,我想要获取给定对象的NSIndexSet(多个索引)。类似于以下内容:
- (NSIndexSet *)indexesOfObjects:(NSArray *)objects

对于NSArray,不存在这种方法。我是否漏掉了什么?有人知道其他标准方法吗?否则我就要将其写成类别方法。

3个回答

13

较新的NSArray版本(OSX 10.6和iOS 4)提供了indexesOfObjectsPassingTest:方法。

NSIndexSet *indexesOfObjects = [[array1 indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
    return [array2 containsObject:obj];
}];

6

使用集合来指定要查找的对象可能是有用的,例如:

- (NSIndexSet *) indicesOfObjectsInSet: (NSSet *) set
{
    if ( [set count] == 0 )
        return ( [NSIndexSet indexSet] );

    NSMutableIndexSet * indices = [NSMutableIndexSet indexSet];

    NSUInteger index = 0;
    for ( id obj in self )
    {
        if ( [set containsObject: obj] )
            [indices addIndex: index];

        index++;
    }

    return ( [[indices copy] autorelease] );
}

这需要访问数组中的每个对象,但至少只需访问一次,并在执行此操作时利用快速枚举。使用NSSet并将数组中的每个对象与该集合进行测试,比测试是否包含在数组中要快得多。
这里有一个潜在的优化方法,但在接收数组中存储单个对象多次的情况下会出现问题:
if ( [set containsObject: obj] )
{
    [indices addIndex: index];
    if ( [indices count] == [set count] )
        break;
}

那么,如果你在一个包含20,000个项目的数组中扫描两个对象,并且它们都在前十个项目中,那么你将能够避免扫描数组中的其他19,990个对象。不过,正如我所说的,如果数组包含重复项,则无济于事,因为它一旦找到2个索引(即使它们都指向同一个对象),就会停止搜索。

话虽如此,我同意上面Mike的评论。很可能在优化时会遇到一些麻烦。值得考虑使用不同的数据类型;例如,虽然NSArray似乎是一个简单平坦容器的最合理选择,但如果实际上不需要排序信息,则最好使用NSSet;这样做的另一个好处是它不会存储相同的对象(使用-isEqual:来计算)。如果确实想要跟踪重复项,但不需要排序,则可以使用NSCountedSet,它的行为类似于NSSet,但它会记录每个对象已添加/删除的次数,而不会实际存储重复项。


2
只是一个小注:在英语中,“indexes”和“indices”都是正确的,但Cocoa始终使用“indexes”,因此最好保持这个术语,至少对于方法名称。 - Quinn Taylor

1

据我所见,您需要实现自己的类别。


2
请注意,希望使用此方法是设计缺陷的强烈迹象。-indexOfObject:通过搜索数组中的每个对象来工作,因此对于大型数组或多个搜索而言变得非常缓慢。重新考虑您的数据结构,寻找更合理的解决方案。 - Mike Abdullah

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