iPhone OS: выборка случайного экземпляра объекта с использованием NSPredicate Nsfetchrequest и основных данных - PullRequest
11 голосов
/ 14 мая 2010

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

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

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

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

дайте мне знать, если вам нужно больше деталей.

Спасибо!

Ник

Ответы [ 5 ]

20 голосов
/ 06 марта 2011

Вместо этого используйте 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];
5 голосов
/ 14 мая 2010

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

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

#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 с.

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

2 голосов
/ 24 февраля 2015

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

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

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

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

  5. Переберите массив случайных objectID и используйте NSManagedObjectContext objectWithID: для получения объектов.
0 голосов
/ 30 апреля 2013

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

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

0 голосов
/ 14 декабря 2010

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

myEntityCount = [myEntities count]
...