2012-06-27 17 views
8

Tôi không chắc chắn về cách hoạt động của NSSet anyObject. Có nghĩa là gì "Đối tượng được trả về được chọn tại sự thuận tiện của bộ" (từ NSSet class reference)?NSSet làm thế nào để trích xuất đối tượng một cách ngẫu nhiên?

Hơn nữa, làm cách nào để trích xuất các đối tượng một cách ngẫu nhiên từ một NSSet? Tôi đã suy nghĩ về việc nhận được allObjects trong một mảng và sau đó là myArray[arc4random_uniform(x)] trong đó x là số đối tượng trong mảng.

+0

Bạn có đồng ý lặp lại không? – Richard

+0

Thay vì tò mò về bản thân mình, tôi đoán bạn có thể gọi anyObject một số lần ngẫu nhiên nhưng giải pháp mảng của bạn nghe có vẻ tốt hơn. – Patrick

+0

Tôi đoán việc chuyển đổi NSArray thành NSSet qua lại không phải là cách hay để trộn lẫn. –

Trả lời

13

Thông thường, NSSet trường hợp được tạo bằng sự ủng hộ CFHash, vì vậy chúng hầu như luôn trả về đối tượng đầu tiên trong băm đó vì đây là tìm kiếm nhanh nhất. Lý do nó nói

Đối tượng được trả về được chọn theo sự thuận tiện của bộ — lựa chọn không được đảm bảo là ngẫu nhiên.

Bởi vì bạn không phải lúc nào cũng biết nó sẽ có mảng sao lưu. Đối với tất cả những gì bạn biết, ví dụ NSSet bạn có một bản sao NSDictionary hoặc một số cấu trúc dữ liệu tương tự khác. Vì vậy, trong kết luận, nếu bạn cần một đối tượng ngẫu nhiên từ NSSet, không sử dụng -anyObject, thay vào đó hãy sử dụng allObjects: và sau đó trộn mảng đó.

+0

Có! Tôi nghĩ rằng điều này đặt tôi vào giới hạn đại diện cho ngày hôm nay! –

+0

Bây giờ bạn có thể đi ngủ :) – Anne

+0

@Anne nope, bây giờ là lúc để làm điều đó trên meta! –

4

Các tài liệu đọc mà anyObject lợi nhuận

Một trong những đối tượng trong tập hợp, hoặc nil nếu tập không chứa đối tượng. Đối tượng được trả lại được chọn theo sự thuận tiện của bộ - lựa chọn không được đảm bảo là ngẫu nhiên.

Rất có thể có một số thuật toán xác định trong công việc.

Điều đáng tin cậy nhất để làm sẽ là, như bạn đề nghị, để tạo ra một NSArray bằng cách sử dụng phương pháp NSSetallObjects, và sau đó chọn một yếu tố ngẫu nhiên từ đó với arc4random() % N nơi Ncount của NSArray.

+4

Tốt hơn để sử dụng arc4random_uniform thay vì chỉ sử dụng toán tử modulo, như fabio được đề xuất trong câu hỏi của mình, để tránh sai số modulo. – Sven

14

Trích từ NSSet Class Reference:

Đối tượng quay trở lại được chọn vào lúc của bộ thuận tiện-sự lựa chọn không đảm bảo được ngẫu nhiên.

Để "ngẫu nhiên", hãy chuyển đổi NSSet thành NSArray bằng cách sử dụng [theSet allObjects].
Tiếp theo, chọn bất kỳ đối tượng nào một cách ngẫu nhiên bằng cách sử dụng arc4random_uniform().

+2

Cho phép công bằng ở đây, bạn cũng sẽ cần phải khởi chạy trình ngẫu nhiên khác nhau mỗi lần khởi động cho nó thực sự là ngẫu nhiên, và thậm chí sau đó, nó là giả ngẫu nhiên :-) +1 – trumpetlicks

1

tôi sử dụng arc4random() và hai mảng có thể thay đổi để có được một tập hợp ngẫu nhiên và độc đáo của các đối tượng:

NSMutableArray *selectionPool = ...; 

int numberOfObjectsToSelect = x; 

NSMutableArray *selectedObjects = [[NSMutableArray alloc] initWithCapacity:numberOfObjectsToSelect]; 

int modulus = selectionPool.count - 1; 

for (int i = 0; i < numberOfObjectsToSelect; i++) { 

    int j = arc4random() % (modulus--); 
    [selectedObjects addObject:[selectionPool objectAtIndex:j]]; 
    [selectionPool removeObjectAtIndex:j]; 

} 

Tôi không chắc chắn như thế nào hiệu quả nó sẽ là bộ sưu tập lớn, nhưng nó làm việc cho tôi với các bộ sưu tập có số lượng trong 100 đối tượng thấp.

+0

sẽ nhận được phân chia bằng không ngoại lệ nếu 'numberOfObjectsToSelect == selectionPool.count' –