Получить NSIndexSet из NSArray
-
05-09-2019 - |
Вопрос
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
.Я что-то пропустил?Кто-нибудь знает другой стандартный метод?В противном случае мне придется записать это как метод категории.
Решение
Возможно, было бы полезно реализовать его, используя набор для указания объектов для поиска, например:
- (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:
) дважды.Если вы хотите отслеживать дубликаты, но не нуждаетесь в упорядочивании, вы можете использовать NSCountedSet, который ведет себя как NSSet, за исключением того, что он отслеживает, сколько раз каждый объект был добавлен/удален, без фактического сохранения дубликатов.
Другие советы
Более новые версии NSArray (OSX 10.6 и iOS 4) предоставляют indexesOfObjectsPassingTest:
метод.
NSIndexSet *indexesOfObjects = [[array1 indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return [array2 containsObject:obj];
}];
Насколько я понимаю, вам нужно реализовать свою собственную категорию.