Reputation: 7717
I am not sure about how NSSet's anyObject
work. What does it mean that "The object returned is chosen at the set’s convenience" (from the NSSet class reference) ?
Further, how can I best extract objects randomly from a NSSet? I was thinking about getting allObjects
in an array and then myArray[arc4random_uniform(x)]
where x is the number of objects in the array.
Upvotes: 8
Views: 4578
Reputation: 27073
Quote from NSSet Class Reference:
The object returned is chosen at the set’s convenience—the selection is not guaranteed to be random.
For "randomness", convert the NSSet
to an NSArray
using [theSet allObjects]
.
Next, pick any object randomly using arc4random_uniform()
.
Upvotes: 14
Reputation: 594
I use arc4random() and two mutable arrays to get a random and unique set of objects:
NSMutableArray *selectionPool = ...;
int numberOfObjectsToSelect = x;
NSMutableArray *selectedObjects = [[NSMutableArray alloc] initWithCapacity:numberOfObjectsToSelect];
int modulus = selectionPool.count - 1;
for (int i = 0; i < numberOfObjectsToSelect; i++) {
int j = arc4random() % (modulus--);
[selectedObjects addObject:[selectionPool objectAtIndex:j]];
[selectionPool removeObjectAtIndex:j];
}
I'm not sure how efficient it would be for large collections, but it's worked for me with collections that number in the low 100s of objects.
Upvotes: 1
Reputation: 55583
Usually, NSSet
instances are created with a CFHash
backing, so they almost always return the first object in that hash, as it is the fastest to look up. The reason it says
The object returned is chosen at the set’s convenience—the selection is not guaranteed to be random.
Is because you don't always know it will have a backing array. For all you know, the NSSet
instance you have has a NSDictionary
backing it, or some other similar data structure.
So, in conclusion, if you need a random object from a NSSet
, don't use -anyObject
, instead use allObjects:
and then shuffle that array.
Upvotes: 13
Reputation: 48398
The documentation reads that anyObject
returns
One of the objects in the set, or nil if the set contains no objects. The object returned is chosen at the set’s convenience—the selection is not guaranteed to be random.
Most likely there is some deterministic algorithm at work.
The most reliable thing to do would be, as you suggest, to create an NSArray
using the NSSet
method allObjects
, and then choose a random element from that with arc4random() % N
where N
is the count
of the NSArray
.
Upvotes: 4