我需要从NSIndexSet
中包含的随机索引中选择一个随机索引。
作为参考,(事实证明-anyObject不能保证从集合中返回一个随机对象。)NSSet
定义了从集合中挑选任意对象的-anyObject
方法(documentation)。 NSIndexSet
中是否有类似的功能?
如果没有,怎么可以实施?
注意:我找到了一个实现here,但它涉及对索引集元素的迭代。理想情况下,我想避免枚举。
修改:令我失望的是,NSSet
的文档指出-anyObject
无法保证从集合中返回随机对象。不幸的是,可以从NSIndexSet
documentation, regarding the implementation of -getIndexes:maxCount:inIndexRange:
答案 0 :(得分:0)
首先在0
和[indexSet count]-1
之间生成一个随机数。
现在从indexSet获取randomNum
索引处的索引。这样没有indexAtIndex:
方法,但是这段代码会给你一个类似的结果:
NSUInteger index = [indexSet firstIndex];
for (NSUInteger i = 0, target = randomNum; i < target; i++)
index = [indexSet indexGreaterThanIndex:index];
另请查看this question。
答案 1 :(得分:0)
你可以在较低的层面做一些事情,为索引手动分配/释放一些内存而不进行任何枚举,这也提供了随机索引:
NSIndexSet *_set = ... // your input index set
NSUInteger *_integerCArray = malloc(_set.count * sizeof(NSUInteger));
#if __LP64__
NSRange _indicesRange = NSMakeRange(0, UINT64_MAX);
#else
NSRange _indicesRange = NSMakeRange(0, UINT32_MAX);
#endif
[_set getIndexes:_integerCArray maxCount:_set.count inIndexRange:&_indicesRange];
NSInteger _randomIndex = _integerArray[arc4random_uniform((u_int32_t)_set.count)]; // the random index
free(_integerCArray), _integerCArray = nil;
我知道你告诉过你对枚举不感兴趣,并且公平地认为它不是一种非常有效的方式,但它肯定会根据你的需要为你提供随机索引在这种情况下,更好地阅读和内存管理更安全:
NSIndexSet *_set = ... // your input index set
__block NSInteger _counter = arc4random_uniform((u_int32_t)_set.count); // assume there are fewer indices in the set than UINT32_MAX
NSInteger _randomIndex = [_set indexPassingTest:^BOOL(NSUInteger idx, BOOL * _Nonnull stop) {
return --_counter < 0;
}];
注意:如果随机计数器大于O(n/2)
,则可以使用NSEnumerationReverse
选项针对_set.count / 2
优化此提示,但我不担心在这个答案,如果这个集合基本上是巨大的,这可能是一个好主意,但有几百个索引,你甚至不会麻烦使用这个笨拙的解决方案。