NSIndexSet "-indexAtIndex:"?

Это кажется глупым вопросом, потому что мне кажется, что мой случай использования должен быть довольно распространенным.

Скажем, я хочу представить разреженный набор индексов с NSIndexSet (что, конечно же, для чего). Я могу использовать -firstIndex для получения самого низкого значения и -lastIndex для самого высокого значения, но канонический способ получить один, произвольный индекс посередине, учитывая его "индекс"? Документы оставили меня неясными.

например. если у меня есть индекс с индексами {0, 5, 8, 10, 12, 28}, и я хочу сказать "дайте мне четвертый индекс", и я ожидаю, что вернусь 10 (или 12, полагаю, зависит о том, считаю ли я нуль, но не вдаваться в это, вы знаете, что я имею в виду).

Обратите внимание, что я не делаю "перечисление" во всем наборе индексов. В данный момент времени я просто хочу знать, что n-й индекс в наборе задан численным порядком.

Возможно, моя структура данных неверна ( "set" s обычно не предназначены для такого упорядоченного доступа), но, похоже, NSIndexArray не говорит.

Я пропустил что-то очевидное?

Спасибо!

Ответы

Ответ 1

Я считаю, что NSIndexSet хранит свои индексы с использованием диапазонов, поэтому нет необходимости быстро возвращать индекс nth. Вы можете перечислить счетчик, пока ваш счетчик не достигнет вашего целевого индекса:

NSUInteger index = [indexSet firstIndex];

for (NSUInteger i = 0, target = 4; i < target; i++)
  index = [indexSet indexGreaterThanIndex:index];

Это должно дать вам 4-й индекс. Вы даже можете добавить метод как метод категории, если хотите:

- (NSUInteger)indexAtIndex:(NSUInteger)anIndex
{
    if (anIndex >= [self count])
      return NSNotFound;

    NSUInteger index = [indexSet firstIndex];
    for (NSUInteger i = 0; i < anIndex; i++)
      index = [self indexGreaterThanIndex:index];
    return index;
}

Но, как вы сказали, это может быть не лучшая структура данных, поэтому подумайте об этом больше, прежде чем переходить к чему-то вроде этого.

Ответ 2

NSIndexSet не предназначен для такого доступа. Обычно вы перечисляете индексы в наборе следующим образом:

NSUInteger idx = [theSet indexGreaterThanOrEqualToIndex: 0];
while (idx != NSNotFound) {
    // idx equals the next index in the set.
    idx = [theSet indexGreaterThanIndex: idx];
}

@Рихард указывает, что этот цикл for проще:

for (NSUInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex:i]) {
    // i equals the next index in the set.
}

Есть некоторые основанные на блоке методы, которые являются новыми для NSIndexSet по сравнению с Mac OS X 10.6/iOS 4.0, но я пока не рассматривал их.

Это должно быть тривиально изменить приведенный выше пример, чтобы поддерживать количество индексов и останавливаться, когда достигнет четвертого индекса в наборе.;)

Ответ 3

Скажем, я хочу представить разреженный набор индексов с NSIndexSet (что, конечно же, для него).

[мой акцент]

Собственно, нет, нет. documentation говорит следующее:

Вам не следует использовать наборы индексов для хранения произвольного набора целых значений, поскольку индексы устанавливают индексы как отсортированные диапазоны.

Итак, если вы используете его для хранения разреженного массива целых чисел, он довольно неэффективен. Кроме того, единственный способ получить n-й индекс - перебирать с одного конца. Вам будет лучше использовать массив.

Ответ 4

Еще одно решение:

- (NSUInteger)indexAtIndex:(NSUInteger)index {
   __block NSUInteger result = NSNotFound;
   __block NSUInteger aCounter = 0;

   [self enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) {
      if (aCounter == index) {
         result = idx;
         *stop = YES;

      } else {
         aCounter++;
      }
   }];

   return result;
}