views:

416

answers:

2

Working on an app where I have a large collections of managed objects against which I want to fetch a few random instances.

My question is, is there any way I can use NSPredicate and NSFetchRequest to return several objects at random.

I saw that you could actually add a NSFetchRequest into the entity using the data modeler, any way to do the random fetch using this?

Also what would be the best method for determining the "count" of a table so I can set the bounds of the random number generator.

let me know if you need more details.

Thanks!

Nick

+2  A: 

This may not be exactly how you implement this, but hopefully it will get you started.

Somewhere in your header or at the top of your implementation file:

#import <stdlib.h>
#import <time.h>

Elsewhere in your implementation:

//
// get count of entities
//
NSFetchRequest *myRequest = [[NSFetchRequest alloc] init];
[myRequest setEntity: [NSEntityDescription entityForName:myEntityName inManagedObjectContext:myManagedObjectContext]];
NSError *error = nil;
NSUInteger myEntityCount = [myManagedObjectContext countForFetchRequest:myRequest error:&error];    
[myRequest release];

//
// add another fetch request that fetches all entities for myEntityName -- you fill in the details
// if you don't trigger faults or access properties this should not be too expensive
//
NSArray *myEntities = [...];

//
// sample with replacement, i.e. you may get duplicates
//
srandom(time(NULL)); // seed random number generator, so that you get a reasonably different series of random integers on each execution
NSUInteger numberOfRandomSamples = ...;
NSMutableSet *sampledEntities = [NSMutableSet setWithCapacity:numberOfRandomSamples];
for (NSInteger sampleIndex = 0; sampleIndex < numberOfRandomSamples; sampleIndex++) {
    int randomEntityIndex = random() % myEntityCount; // generates random integer between 0 and myEntityCount-1
    [sampledEntities addObject:[myEntities objectAtIndex:randomEntityIndex]];
}

// do stuff with sampledEntities set

If you need to sample without replacement, to eliminate duplicates, you might create an NSSet of randomEntityIndex NSNumber objects, instead of just sampling random ints.

In this case, sample from an ordered NSSet, remove NSNumber objects as you pull them out of the bag, and decrement myEntityCount for the purposes of picking a random NSNumber object from the set.

Alex Reynolds
Hey Alex thanks so much, very cool! This looks like it should work perfectly. My only concern is that the myEntities array will contain anywhere from 3k-5k instances, even with that many pieces of data are you thinking it will not get too crappily slow? I was ideally hoping to perform the random selection without grabbing every entity instance, am i barking up the wrong tree here? Thanks again Alex!
nickthedude
Extra info: the things I'm trying to grab are objects with two properties, an nsstring any where from 1-50 chars long, and a pseudo primary key int I thought might help with the random selection bit. I can restructure the model though if necessary still prototyping this sucker.
nickthedude
You could definitely use the pseudo-primary-key attribute instead of grabbing all records.
Alex Reynolds
Cool, I'll report back what I end up doing, I'm reading this core data book and trying not to gauge my eyes out. cool.
nickthedude
The objects returned by Core Data will be empty except for their `-objectID` property and therefore the response will be very quick. Only the objects that you are accessing attributes on will be fully realized and pulled into memory.
Marcus S. Zarra
A: 

This article about random fetching could be helpful for the problem.

slatvick