2010-05-13 24 views
10

Làm việc trên một ứng dụng mà tôi có một bộ sưu tập lớn các đối tượng được quản lý mà tôi muốn tìm nạp một vài trường hợp ngẫu nhiên.Hệ điều hành iPhone: Tìm nạp một thực thể ngẫu nhiên bằng NSPredicate Nsfetchrequest và dữ liệu lõi

Câu hỏi của tôi là, có cách nào tôi có thể sử dụng NSPredicate và NSFetchRequest để trả lại một số đối tượng một cách ngẫu nhiên hay không.

Tôi thấy rằng bạn thực sự có thể thêm NSFetchRequest vào thực thể bằng cách sử dụng trình tạo mô hình dữ liệu, bất kỳ cách nào để thực hiện tìm nạp ngẫu nhiên bằng cách sử dụng này?

Ngoài ra, phương pháp nào tốt nhất để xác định "đếm" của bảng để tôi có thể đặt giới hạn của trình tạo số ngẫu nhiên.

cho tôi biết nếu bạn cần thêm chi tiết.

Cảm ơn!

Nick

+0

Thông tin thêm: những thứ tôi đang cố gắng lấy là đối tượng có hai thuộc tính, một chuỗi nsstring bất kỳ từ 1-50 ký tự dài và khóa giả chính int tôi nghĩ có thể trợ giúp với bit lựa chọn ngẫu nhiên. Tôi có thể tái cơ cấu mô hình mặc dù nếu cần thiết vẫn còn prototyping sucker này. – nickthedude

+0

Nhận xét này nên được thêm vào câu hỏi của bạn. –

Trả lời

5

Đây có thể không chính xác cách bạn triển khai, nhưng hy vọng nó sẽ giúp bạn bắt đầu.

Một nơi nào đó trong tiêu đề của bạn hoặc ở phía trên cùng của tập tin thực thi của bạn:

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

Ở những nơi khác trong việc thực hiện của bạ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 

Nếu bạn cần để lấy mẫu mà không cần thay thế, để loại bỏ bản sao, có lẽ bạn tạo các đối tượng NSSet của randomEntityIndexNSNumber thay vì chỉ lấy mẫu ngẫu nhiên int s.

Trong trường hợp này, mẫu từ một lệnh NSSet, loại bỏ NSNumber đối tượng như bạn kéo chúng ra khỏi túi, và giảm giá trị myEntityCount nhằm mục đích chọn một đối tượng ngẫu nhiên NSNumber từ tập.

+0

Hey Alex cảm ơn rất nhiều, rất tuyệt! Điều này có vẻ như nó sẽ hoạt động hoàn hảo. Mối quan tâm duy nhất của tôi là mảng myEntities sẽ chứa bất cứ nơi nào từ các trường hợp 3k-5k, ngay cả với nhiều mẩu dữ liệu đó bạn nghĩ rằng nó sẽ không quá chậm chạp? Tôi đã được lý tưởng hy vọng để thực hiện lựa chọn ngẫu nhiên mà không grabbing mỗi thể hiện thực thể, tôi sủa lên cây sai ở đây? Cảm ơn Alex lần nữa! – nickthedude

+0

Thông tin thêm: những thứ tôi đang cố gắng lấy là các đối tượng có hai thuộc tính, một chuỗi nsstring bất kỳ từ 1-50 ký tự dài và một khóa chính giả tôi nghĩ có thể giúp với bit chọn ngẫu nhiên. Tôi có thể tái cơ cấu mô hình mặc dù nếu cần thiết vẫn còn prototyping sucker này. – nickthedude

+0

Bạn chắc chắn có thể sử dụng thuộc tính giả-khóa-chính thay vì lấy tất cả các bản ghi. –

0

Nếu bạn vẫn đang tìm nạp tất cả các đối tượng, không cần yêu cầu đầu tiên để nhận số đối tượng. Bạn chỉ có thể sử dụng một cái gì đó như:

myEntityCount = [myEntities count] 
19

Thay vì sử dụng fetchLimit kết hợp với fetchOffset cách mà bạn có hiệu quả có thể lấy chỉ là một thực thể duy nhất vào bộ nhớ:

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

Tôi đã thử phương pháp này lấy một đối tượng ngẫu nhiên bởi vì tôi nghĩ rằng nó sẽ có chi phí thấp hơn nhiều so với liên tục tìm nạp lại toàn bộ danh sách của tôi hơn 5k mục để kéo ra một đối tượng ngẫu nhiên. Tuy nhiên, những gì tôi thấy là dù tôi có nhận được khoản chênh lệch nào thì tôi cũng sẽ luôn nhận được một trong mười đối tượng được quản lý tương tự. Phương pháp tạo các đối tượng ngẫu nhiên này không có nghĩa là 'ngẫu nhiên' và do đó, cho việc sử dụng của tôi, không thể chấp nhận được. Các chi phí từ sau câu trả lời được chấp nhận là tối thiểu, ít nhất là ít hơn nhiều so với tôi đã nghĩ. Do đó, tôi sẽ đề nghị câu trả lời được chấp nhận cho câu trả lời này. – Krejko

+0

Tôi cũng gặp rắc rối với điều này ... Tôi cần phải lấy một mục ngẫu nhiên từ các cá thể dữ liệu cốt lõi của mình và tạo ra một phương thức gần như giống với Corey Floyd nói, nhưng có vẻ như có cái gì đó mà CoreData không thích và nó không trả về kết quả mong đợi ... –

+0

+1 cho câu trả lời này, nhưng nó cần một sửa chữa nhỏ, khi bù được tính bằng myEntityCount, tìm nạp sẽ trả về 0 bản ghi, ít nhất trong trường hợp của tôi, vì vậy tôi trừ 1 từ tính toán bù đắp. Sau đó, bạn cần một kiểm tra nhỏ -> nếu myEntityCount là số không bạn có thể không thực sự nhận được bất kỳ kết quả nào, sau đó bạn cần phải thoát khỏi phương thức trước khi bù đắp được tính toán. – cybercow

0

Giải pháp được đề xuất bởi Core sẽ không hoạt động nếu bạn cần phải ngẫu nhiên tìm nạp trong một bảng tập hợp các hàng bị hạn chế bởi một vị từ (ví dụ: "nơi một cái gì đó < một cái gì đó"). Các giải pháp tốt nhất tôi có cho đến nay (nơi tôi không cần phải lấy tất cả hoặc một số lượng lớn hàng) đang sử dụng lựa chọn ngẫu nhiên dựa trên một khóa chính (khóa học yêu cầu một khóa chính trong bảng, tốt nhất là w/o bất kỳ giá trị bị thiếu).

2

Tôi đã tìm kiếm rất nhiều về điều này, về cơ bản Coredata sẽ không cung cấp cho bạn bất kỳ hàng ngẫu nhiên nào và nó không có nghĩa là. Bạn phải tạo của riêng bạn.

Đây là những gì tôi nghĩ ra, giả sử chúng tôi đang sử dụng NSPredicate và không có khóa duy nhất chính, đây là câu trả lời tốt nhất có thể tôi nghĩ với chi phí thấp nhất.

  1. Đặt NSFetchRequest nhập thành NSManagedObjectID. Tắt mọi thứ, để giảm thiểu chi phí.
  2. Thực hiện yêu cầu tìm nạp với mong muốn biến vị ngữ, Không sử dụng bất kỳ FetchLimit nào.
  3. Từ mảng được nhận NSManagedObjectID. nhận số ngẫu nhiên của các đối tượng. đây là một giải pháp tốt: Get n random objects (for example 4) from nsarray

  4. Bây giờ bạn đã có ngẫu nhiên NSManagedObjectIDs đếm mong muốn của bạn, (mà nhiều hay ít ngẫu nhiên)

  5. Vòng qua các mảng ObjectId ngẫu nhiên và Sử dụng NSManagedObjectContext objectWithID: để có được các đối tượng.
Các vấn đề liên quan