Получить NSIndexSet от NSArray - PullRequest
7 голосов
/ 25 мая 2009

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 голосов
/ 06 февраля 2013

Более новые версии NSArray (OSX 10.6 и iOS 4) предоставляют метод indexesOfObjectsPassingTest:.

NSIndexSet *indexesOfObjects = [[array1 indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
    return [array2 containsObject:obj];
}];
6 голосов
/ 31 мая 2009

Может быть полезно реализовать его, используя набор для указания объектов для поиска, например:

- (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 индекса (даже если они оба указывают на один и тот же объект).

Сказав, что , я согласен с комментарием Майка выше. Скорее всего, вы настраиваете себя на боль и время оптимизации. Возможно, стоит подумать о разных типах данных; например, в то время как NSArray кажется наиболее логичным выбором для простого плоского контейнера, если вам на самом деле не нужна информация для заказа, лучше вместо этого использовать NSSet; это дает дополнительное преимущество: он не будет хранить один и тот же объект (рассчитывается с использованием -isEqual:) дважды. Если вы хотите отслеживать дубликаты, но не нуждаетесь в упорядочении, вы можете использовать NSCountingSet, который работает как NSSet, за исключением того, что он отслеживает, сколько раз каждый объект был добавлен / удален без фактического хранения дубликатов.

1 голос
/ 25 мая 2009

Насколько я вижу, вы должны реализовать свою собственную категорию.

...