IPhone OS: выборка случайного экземпляра объекта с использованием NSPredicate Nsfetchrequest и основных данных

Работа с приложением, где у меня есть большие коллекции управляемых объектов, против которых я хочу получить несколько случайных экземпляров.

Мой вопрос: есть ли способ использовать NSPredicate и NSFetchRequest для возврата нескольких объектов в случайном порядке.

Я видел, что вы действительно можете добавить NSFetchRequest в объект, используя модель данных данных, любым способом сделать случайную выборку с помощью этого?

Также будет лучшим методом определения "подсчета" таблицы, чтобы я мог установить границы генератора случайных чисел.

сообщите мне, если вам нужна дополнительная информация.

Спасибо!

Ник

Ответ 1

Возможно, это не так, как вы это реализуете, но, надеюсь, вам это поможет.

Где-то в вашем заголовке или в верхней части вашего файла реализации:

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

В другом месте вашей реализации:

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

Если вам нужно выполнить выборку без замены, чтобы исключить дубликаты, вы можете создать объект NSSet из randomEntityIndex NSNumber, а не просто выборку случайных int s.

В этом случае образец из упорядоченного NSSet, удалите объекты NSNumber, вытаскивая их из сумки и уменьшая myEntityCount для выбора случайного объекта NSNumber из набора.

Ответ 2

Вместо этого используйте fetchLimit вместе с fetchOffset таким образом, чтобы вы могли эффективно извлекать только один объект в память:

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

Я много искал для этого, по сути, Coredata не даст вам случайных строк, и это не значит. Вы должны создать свой собственный.

Это то, с чем я столкнулся, предполагая, что мы используем NSPredicate, а theres нет первичного уникального ключа, это самый лучший ответ, который я думаю с наименьшими издержками.

  • Установите NSFetchRequest на NSManagedObjectID. Выключите все, чтобы минимизировать накладные расходы.
  • Выполнить запрос на выборку с помощью желаемого предиката , Не использовать FetchLimit.
  • Из полученного массива NSManagedObjectID. получите случайное число объектов. это хорошее решение: Получить n случайных объектов (например, 4) из nsarray

  • Теперь у вас есть случайный NSManagedObjectIDs вашего желаемого счета (более или менее случайный)

  • Прокрутите массив случайных объектов и используйте NSManagedObjectContext objectWithID: для получения объектов.

Ответ 4

Если вы все равно загружаете все объекты, нет необходимости в первом запросе получить счет объекта. Вы можете просто использовать что-то вроде:

myEntityCount = [myEntities count]

Ответ 5

Решение, предложенное Core, не будет работать, если вам нужно рандомизировать выборку в строках таблицы подмножества, ограниченных предикатом (например, "где-то что-то" ).

Лучшее решение, которое у меня есть до сих пор (где мне не нужно загружать все или большое количество строк), использует случайный выбор на основе первичного ключа (конечно, для него требуется первичный ключ в таблице, предпочтительно без учета любые отсутствующие значения).