2009-05-25 12 views
7

NSArray có phương pháp hữu ích để tìm đối tượng để chỉ địnhNhận NSIndexSet từ NSArray

// To find objects by indexes 
- (id)objectAtIndex:(NSUInteger)index 
- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes 

// To find index by object 
- (NSUInteger)indexOfObject:(id)anObject 

Tuy nhiên, tôi muốn nhận được NSIndexSet (nhiều chỉ số) cho các đối tượng nhất định. Một cái gì đó như:

- (NSIndexSet *)indexesOfObjects:(NSArray *)objects 

Phương pháp này không tồn tại cho NSArray. Tui bỏ lỡ điều gì vậy? Có ai biết phương pháp tiêu chuẩn khác không? Nếu không, tôi phải viết nó như một phương thức thể loại.

Trả lời

6

Nó có thể là hữu ích để thực hiện nó bằng cách sử dụng các thiết lập để xác định các đối tượng để tìm, chẳng hạn như:

- (NSIndexSet *) indicesOfObjectsInSet: (NSSet *) set 
{ 
    if ([set count] == 0) 
     return ([NSIndexSet indexSet]); 

    NSMutableIndexSet * indices = [NSMutableIndexSet indexSet]; 

    NSUInteger index = 0; 
    for (id obj in self) 
    { 
     if ([set containsObject: obj]) 
      [indices addIndex: index]; 

     index++; 
    } 

    return ([[indices copy] autorelease]); 
} 

Điều này đòi hỏi thăm mọi đối tượng trong mảng, nhưng ít ra chỉ làm như vậy một lần và tận dụng đếm nhanh trong khi làm như vậy. Sử dụng một NSSet và kiểm tra từng đối tượng trong mảng so với tập hợp đó cũng nhanh hơn nhiều so với việc thử nghiệm để đưa vào một mảng.

Có một tối ưu hóa tiềm năng ở đây, nhưng nó sẽ phá vỡ trong trường hợp một đối tượng duy nhất được lưu trữ trong mảng nhận nhiều lần:

if ([set containsObject: obj]) 
{ 
    [indices addIndex: index]; 
    if ([indices count] == [set count]) 
     break; 
} 

Bằng cách đó, nếu bạn đang quét một 20'000 mục mảng cho hai đối tượng và cả hai đều nằm trong mười đầu tiên, bạn sẽ có thể tránh quét các đối tượng 19'990 khác trong mảng. Như tôi đã nói mặc dù, điều đó không giúp đỡ nếu mảng có chứa bản sao, bởi vì nó sẽ dừng lại ngay sau khi nó được tìm thấy 2 chỉ số (ngay cả khi cả hai đều trỏ đến cùng một đối tượng).

Có nói rằng, tôi đồng ý với nhận xét của Mike ở trên. Rất có thể bạn đang thiết lập cho mình một số cơn đau đến tối ưu hóa thời gian. Nó có thể là giá trị suy nghĩ về các loại dữ liệu khác nhau; ví dụ, trong khi NSArray có vẻ là sự lựa chọn hợp lý nhất cho một container phẳng đơn giản, nếu bạn không thực sự cần thông tin đặt hàng thì tốt hơn nên sử dụng một NSSet thay thế; điều này có thêm lợi thế là nó sẽ không lưu trữ cùng một đối tượng (được tính toán bằng cách sử dụng -isEqual:) hai lần. Nếu bạn muốn theo dõi các bản sao, nhưng không cần đặt hàng, bạn có thể sử dụng NSCountedSet, hoạt động như NSSet ngoại trừ nó theo dõi số lần mỗi đối tượng đã được thêm/xóa mà không lưu trữ bản sao.

+2

+1 Chỉ cần một lưu ý nhỏ: cả "chỉ mục" và "chỉ mục" đều chính xác bằng tiếng Anh, nhưng Cocoa luôn sử dụng "chỉ mục", vì vậy tốt hơn nên giữ cho thuật ngữ đó, ít nhất là cho tên phương thức. –

1

Bạn phải triển khai danh mục của riêng mình, theo như tôi thấy.

+2

Lưu ý rằng việc muốn phương pháp này là dấu hiệu mạnh về lỗi thiết kế. -indexOfObject: hoạt động bằng cách tìm kiếm qua mọi đối tượng trong mảng và do đó trở nên khá chậm đối với một mảng lớn hoặc nhiều tìm kiếm. Suy nghĩ lại cấu trúc dữ liệu của bạn để có điều gì đó hợp lý hơn. –

13

Phiên bản NSArray mới hơn (OSX 10.6 và iOS 4) cung cấp phương thức indexesOfObjectsPassingTest:.

NSIndexSet *indexesOfObjects = [[array1 indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { 
    return [array2 containsObject:obj]; 
}];