【问题标题】:NSIndexSet "-indexAtIndex:"?NSIndexSet“-indexAtIndex:”?
【发布时间】:2010-12-28 16:21:51
【问题描述】:

这感觉像是一个愚蠢的问题,因为在我看来,我的用例一定很常见。

假设我想用一个 NSIndexSet 来表示一组稀疏的索引(这当然是它的用途)。我可以使用-firstIndex 来获得最低的,-lastIndex 来获得最高的,但是在给定它的“索引”的情况下,在中间获得单个任意索引的规范方法是什么?文档让我不清楚。

例如如果我有一个带有索引 { 0, 5, 8, 10, 12, 28 } 的索引,我想说“给我第四个索引”,我希望得到 10(或 12 我想取决于关于我是否算第零个,但我们不要讨论这个,你知道我的意思)。

请注意,我没有对整个索引集进行“枚举”。在给定的时间点,我只想按数字顺序知道集合中的第 n 个索引是什么。

也许我的数据结构是错误的(“set”通常不是为这种有序访问而设计的),但似乎没有 NSIndexArray 可言。

我是否遗漏了一些明显的东西?

谢谢!

【问题讨论】:

  • @Neilvert:我可能最终会这样做,但是当保存索引的数据结构看起来如此方便时,在 NSNumbers 中对整数进行装箱似乎有点过头了! :)
  • 集合(包括NSIndexSet)是无序的(或者至少,它们的顺序是未定义的)。因此,indexAtIndex: 没有意义,因为这是假设一个有序集(NSIndexSet 不是)。
  • @Dave:总的来说我同意,虽然索引集有点特殊,因为它的内容在语义上是可排序的——而且 NSIndexSet 公开了firstIndexlastIndex ,这是对此的让步。 (内部存储范围的实现说明也是如此)。所以我不觉得indexAtIndex: 就像我在问一个 NSSet 一样荒谬。

标签: objective-c cocoa nsindexset


【解决方案1】:

NSIndexSet 不是为这种访问而设计的。通常,您可以像这样枚举集合中的索引:

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

@Richard 指出这个for 循环更简单:

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

从 Mac OS X 10.6/iOS 4.0 开始,NSIndexSet 有一些新的基于块的方法,但我还没有审查它们。

修改上面的示例以保持索引的运行计数并在到达集合中的第四个索引时停止应该是微不足道的。 ;)

【讨论】:

  • 这几乎说明了一切,尽管我会将代码示例编写为 for 循环:for (NSUInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex:i]) {...}
  • 这也有效。 :) 实际上,这比我的样本更干净。偷东西!
  • 作为提示,如果 indexSet 为 nil,for 循环将无限循环,因为它读取:for (NSUInteger i = 0; i != NSNotFound; i = 0) { }
  • @KyleRobson 您的反对意见同样适用于 while 循环构造。
【解决方案2】:

我相信NSIndexSet 使用范围存储其索引,因此不一定有快速的方法来返回nth 索引。您可以枚举保持一个计数器,直到您的计数器达到您的目标索引:

NSUInteger index = [indexSet firstIndex];

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

这应该给你第四个索引。如果需要,您甚至可以将该方法添加为类别方法:

- (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;
}

但是,正如你所说,这可能不是最好的数据结构,所以在使用这样的东西之前请多考虑一下。

【讨论】:

  • 是的,听起来我并没有遗漏一些明显的东西。不幸的是,如果它在内部将索引存储为范围,则它可以比我在类别中更有效地公开 indexAtIndex,但要注意。谢谢。
【解决方案3】:

假设我想用 NSIndexSet (这当然是它的用途)表示一组稀疏的索引

[我的重点]

实际上,不是。 documentation 是这样说的:

您不应该使用索引集来存储整数值的任意集合,因为索引集将索引存储为排序范围。

所以如果你用它来存储一个稀疏的整数数组,它是非常低效的。此外,获得第 n 个索引的唯一方法是从一端迭代。最好使用数组。

【讨论】:

  • Pshaw,语义学!如果我只需要一组已知的连续索引,我会使用 NSRange。 :) 课堂上的其他方法对我来说很有价值,但我也想要这种按位置获取的行为,尽管我觉得它不存在。
【解决方案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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多