2010-05-13 12 views
10

Trabajando en una aplicación donde tengo una gran colección de objetos administrados contra los cuales quiero buscar algunas instancias aleatorias.iPhone OS: recuperación de una instancia de entidad aleatoria utilizando NSPredicate Nsfetchrequest y core data

Mi pregunta es, ¿hay alguna manera de que pueda usar NSPredicate y NSFetchRequest para devolver varios objetos al azar.

Vi que en realidad podría agregar una NSFetchRequest en la entidad utilizando el modelador de datos, ¿hay alguna manera de hacer la búsqueda aleatoria usando esto?

También, ¿cuál sería el mejor método para determinar el "recuento" de una tabla para poder establecer los límites del generador de números aleatorios.

hágamelo saber si necesita más detalles.

Gracias!

Nick

+0

Información adicional: las cosas que intento capturar son objetos con dos propiedades, una nsstring en cualquier lugar de 1-50 caracteres de largo, y una clave pseudoprimaria int que pensé que podría ayudar con el bit de selección al azar. Puedo reestructurar el modelo aunque, si es necesario, aún crear prototipos de este tonto. – nickthedude

+0

Este comentario debe agregarse a su pregunta. –

Respuesta

5

Esto puede no ser exactamente cómo se implementa esto, pero espero que le ayudará a empezar.

En algún lugar en el encabezado o en la parte superior de su archivo de aplicación:

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

En otras partes de su aplicación:

// 
// 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 

Si necesita probar sin reemplazo, para eliminar duplicados, es posible que crear un NSSet de randomEntityIndexNSNumber objetos, en lugar de solo muestrear aleatoriamente int s.

En este caso, a partir de una muestra de NSSet ordenada, retire NSNumber objetos a medida que los saca de la bolsa, y decremento myEntityCount a los efectos de recoger un objeto NSNumber azar del conjunto.

+0

¡Hola Alex, muchas gracias, genial! Esto parece que debería funcionar perfectamente. Mi única preocupación es que el conjunto de myEntities contendrá desde instancias de 3k-5k, incluso con esa cantidad de datos ¿cree que no será demasiado lenta? Estaba idealmente esperando realizar la selección aleatoria sin tener que agarrar cada instancia de entidad, ¿estoy ladrando el árbol equivocado aquí? Gracias de nuevo Alex! – nickthedude

+0

Información adicional: las cosas que intento capturar son objetos con dos propiedades, una nsstring de entre 1 y 50 caracteres de longitud, y una clave pseudoprimaria int que pensé podría ayudar con el bit de selección aleatoria. Puedo reestructurar el modelo aunque, si es necesario, aún crear prototipos de este tonto. – nickthedude

+0

Definitivamente podría usar el atributo pseudo-primary-key en lugar de agarrar todos los registros. –

0

Si va a buscar todos los objetos de todos modos, no hay necesidad de la primera solicitud para obtener el recuento de objetos. Usted sólo puede usar algo como:

myEntityCount = [myEntities count] 
19

lugar de utilizar el fetchlimit en conjunto con el FetchOffset de esa manera se puede recuperar de manera eficiente sólo una única entidad en la memoria:

NSFetchRequest *myRequest = [[NSFetchRequest alloc] init]; 
[myRequest setEntity: [NSEntityDescription entityForName:myEntityName inManagedObjectContext:myManagedObjectContext]]; 
NSError *error = nil; 
NSUInteger myEntityCount = [myManagedObjectContext countForFetchRequest:myRequest error:&error];  

NSUInteger offset = myEntityCount - (arc4random() % myEntityCount); 
[myRequest setFetchOffset:offset]; 
[myRequest setFetchLimit:1]; 

NSArray* objects = [myManagedObjectContext executeFetchRequest:myRequest error:&error];  
id randomObject = [objects objectAtIndex:0]; 
+3

Intenté este método de buscar un objeto aleatorio porque pensé que tendría mucho menos sobrecarga que continuamente recuperar mi lista completa de más de 5k entradas para extraer un objeto aleatorio. Sin embargo, lo que encontré fue que no importaba cuál fuera el offset, siempre recibiría uno de los mismos diez objetos administrados. Este método de generar objetos aleatorios no era de ninguna manera 'aleatorio' y, por lo tanto, para mi uso, inaceptable. La sobrecarga de seguir la respuesta aceptada fue mínima, al menos mucho menos de lo que había pensado. Debido a esto, recomendaría la respuesta aceptada sobre este. – Krejko

+0

También estoy teniendo problemas con esto ... Necesitaba obtener un elemento aleatorio de mis instancias de datos centrales y creé un método que hacía casi lo mismo que Corey Floyd dice, pero parece que hay algo que no le gusta a CoreData y no devuelve el resultado esperado ... –

+0

+1 para esta respuesta, pero necesita una pequeña corrección, cuando la compensación calculada es igual a myEntityCount, la búsqueda devolverá cero registros, al menos en mi caso, por lo que resté 1 del desplazamiento calculado. Entonces necesita otra verificación pequeña -> si myEntityCount es cero, en realidad no puede obtener ningún resultado, entonces necesita salir del método antes de que se calcule la compensación. – cybercow

0

solución sugerida por Core no funcionará si necesita aleatorizar la búsqueda dentro de una tabla de subconjunto filas restringidas por un predicado (por ejemplo, "donde algo < algo").

La mejor solución que tengo hasta ahora (donde no necesito buscar todas o una gran cantidad de filas) es usar la selección aleatoria basada en una clave primaria (por supuesto requiere una clave primaria en la tabla, preferiblemente w/o cualquier valor faltante).

2

He buscado mucho para esto, esencialmente Coredata no te dará filas al azar, y no está destinado a hacerlo. Tienes que crear el tuyo

Esto es lo que se me ocurrió, asumiendo que estamos usando un NSPredicate y no hay una clave única primaria, esta es la mejor respuesta posible, creo que con la menor sobrecarga.

  1. Establecer NSFetchRequest tipo al NSManagedObjectID. Apaga todo, para minimizar la sobrecarga.
  2. Ejecute la solicitud de recuperación con el predicado deseado, No utilice ningún FetchLimit.
  3. De la matriz recibida NSManagedObjectID. obtén tu número aleatorio de objetos. esta es una buena solución: Get n random objects (for example 4) from nsarray

  4. Ahora tienes al azar NSManagedObjectIDs de su conteo deseada, (que son más o menos al azar)

  5. recorrer la matriz IDobjeto azar y utilizar NSManagedObjectContext objectWithID: para conseguir los objetos.
Cuestiones relacionadas