2010-05-13 4 views
10

Lavorando su un'app in cui sono presenti grandi raccolte di oggetti gestiti rispetto ai quali voglio recuperare alcune istanze casuali.SO iPhone: Recupero di un'istanza di entità casuale utilizzando NSPfactre Nsfetchrequest e dati di base

La mia domanda è, c'è un modo per utilizzare NSPredicate e NSFetchRequest per restituire diversi oggetti in ordine casuale.

Ho visto che si potrebbe effettivamente aggiungere un NSFetchRequest all'entità utilizzando il modellatore dati, un modo per eseguire il recupero casuale usando questo?

Anche quale sarebbe il metodo migliore per determinare il "conteggio" di una tabella in modo da poter impostare i limiti del generatore di numeri casuali.

fatemi sapere se avete bisogno di maggiori dettagli.

Grazie!

Nick

+0

Ulteriori informazioni: le cose che sto cercando di ottenere sono oggetti con due proprietà, una stringa qualsiasi da 1 a 50 caratteri e una chiave primaria pseudo che ho pensato potrebbe aiutare con il bit di selezione casuale. Riesco a ristrutturare il modello anche se, se necessario, ancora prototipando questo ventosa. – nickthedude

+0

Questo commento dovrebbe essere aggiunto alla tua domanda. –

risposta

5

Questo potrebbe non essere esattamente come si implementa questa, ma si spera che permette di iniziare.

qualche parte nel vostro nell'intestazione o nella parte superiore del file di implementazione:

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

Altrove nell'implementazione:

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

Se è necessario campionare senza sostituzione, di eliminare i duplicati, si potrebbe creare un oggetto randomEntityIndexNSNumber di oggetti NSSet, anziché campionare casualmente int s.

In questo caso, il campione da una ordinata NSSet, rimuovere NSNumber oggetti durante si tira fuori dalla borsa, e decrementa myEntityCount ai fini di scegliere un NSNumber oggetto casuale dal set.

+0

Hey Alex grazie mille, molto bello! Sembra che dovrebbe funzionare perfettamente. La mia unica preoccupazione è che l'array myEntities conterrà ovunque da istanze di 3k-5k, anche se molti dati ci stanno pensando che non diventerà troppo lento? Speravo idealmente di eseguire la selezione casuale senza afferrare ogni istanza di entità, sto abbaiando qui sull'albero sbagliato? Grazie ancora Alex! – nickthedude

+0

Ulteriori informazioni: le cose che sto cercando di afferrare sono oggetti con due proprietà, una stringa qualsiasi da 1 a 50 caratteri e una chiave primaria pseudo che ho pensato potrebbe aiutare con il bit di selezione casuale. Riesco a ristrutturare il modello anche se, se necessario, ancora prototipando questo ventosa. – nickthedude

+0

Si potrebbe sicuramente usare l'attributo pseudo-chiave primaria invece di afferrare tutti i record. –

0

Se si stanno recuperando tutti gli oggetti in ogni caso, non è necessario per la prima richiesta ottenere il conteggio degli oggetti. Si può solo usare qualcosa come:

myEntityCount = [myEntities count] 
19

invece utilizzare il fetchlimit in combinazione con il fetchOffset in questo modo è possibile recuperare in modo efficiente solo una singola entità in 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

Ho provato questo metodo di recupero di un oggetto casuale perché pensavo che avrebbe avuto un sovraccarico molto inferiore rispetto al recupero continuo dell'intero elenco di oltre 5k voci per estrarre un oggetto casuale. Tuttavia, ciò che ho scoperto è che, indipendentemente dall'offset, ricevo sempre uno degli stessi dieci oggetti gestiti. Questo metodo di generazione di oggetti casuali non era affatto casuale e quindi, per il mio utilizzo, inaccettabile. Il sovraccarico derivante dal seguire la risposta accettata era minimo, almeno molto meno di quanto pensassi. A causa di ciò, raccomanderei la risposta accettata su questo. – Krejko

+0

Ho anche problemi con questo ... Avevo bisogno di ottenere un oggetto casuale dalle mie istanze di dati di base e ho creato un metodo che ha fatto quasi la stessa cosa di Corey Floyd, ma sembra che ci sia qualcosa che a CoreData non piace e non restituisce il risultato previsto ... –

+0

+1 per questa risposta, ma ha bisogno di una piccola correzione, quando l'offset calcolato diventa uguale a myEntityCount, il recupero restituirà zero record, almeno nel mio caso, quindi ho sottratto 1 dall'offset calcolato. Quindi è necessario un altro piccolo controllo -> se myEntityCount è zero, non è possibile ottenere alcun risultato, quindi è necessario uscire dal metodo prima che venga calcolato l'offset. – cybercow

0

soluzione suggerita da Core non funziona se è necessario randomizzare il recupero in una tabella di sottoinsiemi limitata da un predicato (ad esempio "dove qualcosa è <").

La soluzione migliore che ho finora (dove non ho bisogno di recuperare tutto o un numero elevato di righe) utilizza la selezione casuale basata su una chiave primaria (fuori rotta richiede una chiave primaria nella tabella, preferibilmente w/o eventuali valori mancanti).

2

Ho cercato molto per questo, in sostanza Coredata non ti darà righe casuali, e non è pensato per. Devi creare il tuo.

Questo è quello che è venuto fuori con, supponendo che stiamo usando un NSPredicate e non c'è nessuna chiave primaria Unica, questa è la migliore risposta possibile penso con il minimo sovraccarico.

  1. Impostare NSFetchRequest digitare su NSManagedObjectID. Spegni tutto, per ridurre al minimo il sovraccarico.
  2. Eseguire la richiesta di recupero con il predicato desiderato, Non utilizzare alcun FetchLimit.
  3. dall'array NSManagedObjectID ricevuto. ottieni il tuo numero casuale di oggetti. questa è una buona soluzione: Get n random objects (for example 4) from nsarray

  4. Ora hai casuale NSManagedObjectIDs del il valore desiderato, (che sono più o meno casuale)

  5. Loop attraverso l'array objectID casuale e utilizzare NSManagedObjectContext objectWithID: per ottenere gli oggetti.
Problemi correlati