Khi nào thì tốt hơn nên sử dụng NSSet thay vì NSArray?


Câu trả lời:


173

Khi thứ tự của các mục trong bộ sưu tập không quan trọng, các bộ mang lại hiệu suất tốt hơn cho việc tìm kiếm các mục trong bộ sưu tập.

Lý do là một tập hợp sử dụng giá trị băm để tìm các mục (giống như một từ điển) trong khi một mảng phải lặp lại toàn bộ nội dung của nó để tìm một đối tượng cụ thể.


9
log (1) vs log (n)
Rohan-patel

25
@ rohan-patel Đúng là O (1) vs O (n)
Mansurov Ruslan

1
Nếu được đặt hàng: O (1) vs O (logn) vì có thể áp dụng tìm kiếm nhị phân. Nếu không có thứ tự, thì O (1) vs O (n)
baskInEminence

180

Hình ảnh từ Tài liệu của Apple mô tả nó rất tốt:

Bộ sưu tập Objective-C

Arraylà một lệnh (thứ tự được duy trì khi bạn thêm) chuỗi các phần tử

[array addObject:@1];
[array addObject:@2];
[array addObject:@3];
[array addObject:@4];
[array addObject:@6];
[array addObject:@4];
[array addObject:@1];
[array addObject:@2];

[1, 2, 3, 4, 6, 4, 1, 2]

Setlà một danh sách các phần tử riêng biệt (không trùng lặp), không có thứ tự

[set addObject:@1];
[set addObject:@2];
[set addObject:@3];
[set addObject:@4];
[set addObject:@6];
[set addObject:@4];
[set addObject:@1];
[set addObject:@2];

[1, 2, 6, 4, 3]

2
Trong ví dụ của bạn, bạn đang thêm các nguyên thủy vào một mảng và một tập hợp. Không thể vì chúng chỉ có thể chứa các đối tượng.
FreeAsInBeer

10
Cảm ơn bạn đã chỉnh sửa @Zaheer, nhưng nó thực sự không hợp lệ. Tôi đã không thêm các nguyên thủy. Tôi đã thêm các chữ.
James Webster

Lời giải thích tuyệt vời :) +1 :)
Karun

1
Thích lời giải thích của bạn! +1 cho điều đó
nổi loạn

66

Câu trả lời tốt nhất là tài liệu của Apple .

nhập mô tả hình ảnh ở đây

Sự khác biệt chính là NSArraylà một bộ sưu tập lệnh và NSSetlà một bộ sưu tập có thứ tự.

Có một số bài báo nói về sự khác biệt về tốc độ giữa hai loại, như bài báo này . Nếu bạn đang lặp lại một bộ sưu tập không có thứ tự thì NSSetthật tuyệt. Tuy nhiên, trong nhiều trường hợp, bạn cần phải làm những việc mà chỉ an NSArraycó thể làm, vì vậy bạn hy sinh tốc độ cho những khả năng đó.

NSSet

  • Chủ yếu truy cập các mục bằng cách so sánh
  • Không theo thứ tự
  • Không cho phép trùng lặp

NSArray

  • Có thể truy cập các mục theo chỉ mục
  • Đã đặt hàng
  • Cho phép trùng lặp

Đó là tất cả những gì thực sự có! Hãy cho tôi biết nếu nó giúp được bạn.


Bạn không cần phải luôn hy sinh NSSetvì lợi ích của việc lập chỉ mục. Thông thường sử dụng hai cấu trúc dữ liệu khác nhau cho cùng một dữ liệu. Hoặc bạn xây dựng và lập chỉ mục trên mảng đó :) Nhưng sau đó tốt hơn nên sử dụng một DB có triển khai nó.
Sulthan

"Xây dựng chỉ mục trên mảng đó". Bạn không thể tạo chỉ mục trên NSSet. Có nhiều kỹ thuật khác nhau mà bạn có thể sử dụng. Và nếu bạn cần hy sinh CẢ bộ nhớ và sức mạnh xử lý, thì bạn đang làm sai.
Sulthan

Vì câu hỏi là về NSSetNSArray, câu trả lời của tôi là chính xác và đầy đủ. Có, bạn có thể xây dựng các cấu trúc dữ liệu khác, nhưng tôi chỉ so sánh hai cấu trúc này.
woz

Tôi đã ủng hộ nhưng câu trả lời của bạn không chính xác khi bạn nói về sự hy sinh. Nếu bạn cần một số chức năng từ NSArrayvà một số chức năng từ NSSet, câu trả lời đúng không phải là "sử dụng NSArrayvà hy sinh hiệu suất". Câu trả lời là kết hợp cả hai hoặc sử dụng một cấu trúc dữ liệu khác.
Sulthan

Tôi đã nói rằng sự khác biệt chính được thiết lập là cho các đối tượng duy nhất, nơi như một mảng có thể có các bản sao. Khía cạnh thứ tự là thứ yếu trong thực tế đó.
malhal

12

NSOrderedSet có sẵn trong iOS 5+, do đó, sự khác biệt chính là bạn có muốn các đối tượng trùng lặp trong cấu trúc dữ liệu hay không.


9

NSArray :

  1. Thu thập dữ liệu có thứ tự
  2. Cho phép trùng lặp
  3. Nó là đối tượng loại bộ sưu tập

NSSet :

  1. Thu thập dữ liệu không theo thứ tự
  2. Không cho phép trùng lặp
  3. Nó cũng là đối tượng kiểu bộ sưu tập

7

Một mảng được sử dụng để truy cập các mục theo chỉ mục của chúng. Bất kỳ mục nào cũng có thể được chèn nhiều lần vào mảng. Mảng lưu giữ thứ tự của các phần tử của chúng.

Một tập hợp được sử dụng về cơ bản chỉ để kiểm tra xem mục có trong bộ sưu tập hay không. Các mục không có khái niệm về thứ tự hoặc lập chỉ mục. Bạn không thể có một mục trong một bộ hai lần.

Nếu một mảng muốn kiểm tra xem nó có chứa một phần tử hay không, nó phải kiểm tra tất cả các mục của nó. Bộ được thiết kế để sử dụng các thuật toán nhanh hơn.

Bạn có thể tưởng tượng một tập hợp giống như một cuốn từ điển không có giá trị.

Lưu ý rằng mảng và tập hợp không phải là cấu trúc dữ liệu duy nhất. Có những thứ khác, ví dụ như Queue, Stack, Heap, Fibonacci's Heap. Tôi khuyên bạn nên đọc một cuốn sách về thuật toán và cấu trúc dữ liệu.

Xem wikipedia để biết thêm thông tin.


Trên thực tế, một mảng chỉ cần được kiểm tra cho đến khi mục được tìm thấy. Nếu mục IS trong mảng, rất hiếm khi mọi mục cần được kiểm tra.
FreeAsInBeer

Có, như bạn nói "nếu mục nằm trong mảng". Nếu bạn mong đợi điều này, bạn không cần phải kiểm tra xem nó có ở đó hay không. Sự phức tạp của containshoạt động là O(n). Số lần so sánh khi không có trong mảng là n. Số lần so sánh trung bình khi đối tượng nằm trong mảng là n/2. Ngay cả khi đối tượng được tìm thấy, hiệu suất là khủng khiếp.
Sulthan

Hiệu suất sẽ chỉ khủng khiếp với một mảng lớn. Nếu bạn biết mảng có thể trở nên khá lớn, thì có nhiều cách bạn có thể cải thiện hiệu suất của mảng, chẳng hạn như sử dụng một mảng nhiều mảng.
FreeAsInBeer

Nếu phép toán bình đẳng là đắt, bạn sẽ thấy sự khác biệt ngay cả trên các mảng có 3 mục. Và hành vi tương tự như một mảng lớn có thể xảy ra nếu bạn lặp lại thao tác nhiều (ví dụ: sử dụng thao tác trong chu kỳ 'for'). Bạn đã nghe về tính phức tạp của khấu hao chưa? Độ phức tạp vẫn là tuyến tính và hiệu suất rất tệ so với một tập hợp (thường có độ phức tạp không đổi).
Sulthan

Rõ ràng là sẽ có sự khác biệt, tôi chỉ nói rằng ký hiệu o lớn là cấp số nhân; với các mảng nhỏ, sự khác biệt sẽ rất nhỏ. Ngoài ra, NSArrays có lợi thế về tốc độ khác so với NSSets. Như mọi khi, đó là một sự đánh đổi.
FreeAsInBeer

5
NSArray *Arr;
NSSet *Nset;

Arr=[NSArray arrayWithObjects:@"1",@"2",@"3",@"4",@"2",@"1", nil];
Nset=[NSSet setWithObjects:@"1",@"2",@"3",@"3",@"5",@"5", nil];

NSLog(@"%@",Arr);
NSLog(@"%@",Nset);

mảng

2015-12-04 11: 05: 40.935 [598: 15730] (1, 2, 3, 4, 2, 1)

bộ

2015-12-04 11: 05: 43.362 [598: 15730] {(3, 1, 2, 5)}


4

Sự khác biệt chính đã được đưa ra trong các câu trả lời khác.

Tôi chỉ muốn lưu ý rằng do cách các bộ và từ điển được triển khai (tức là sử dụng hàm băm), nên cẩn thận không sử dụng các đối tượng có thể thay đổi cho các khóa.

Nếu một khóa bị đột biến thì hàm băm (có thể) cũng sẽ thay đổi, trỏ đến một chỉ mục / nhóm khác trong bảng băm. Giá trị gốc sẽ không bị xóa và sẽ thực sự được tính đến khi liệt kê hoặc hỏi cấu trúc về kích thước / số lượng của nó.

Điều này có thể dẫn đến một số lỗi thực sự khó xác định.


3

Ở đây, bạn có thể tìm thấy một so sánh khá kỹ lưỡng giữa các cấu trúc NSArrayvà cơ sở dữ liệu NSSet.

Kết luận ngắn gọn:

Có, NSArray nhanh hơn NSSet vì chỉ cần giữ và lặp lại. Nhanh hơn ít nhất là 50% để xây dựng và nhanh hơn 500% để lặp lại. Bài học: nếu bạn chỉ cần lặp lại nội dung, đừng sử dụng NSSet.

Tất nhiên, nếu bạn cần kiểm tra để đưa vào, hãy làm việc chăm chỉ để tránh NSArray. Ngay cả khi bạn cần cả kiểm tra lặp lại và bao gồm, bạn có thể vẫn nên chọn NSSet. Nếu bạn cần giữ cho bộ sưu tập của mình có thứ tự và cũng như kiểm tra để đưa vào, thì bạn nên cân nhắc giữ hai bộ sưu tập (một NSArray và một NSSet), mỗi bộ chứa các đối tượng giống nhau.

NSDictionary được xây dựng chậm hơn NSMapTable - vì nó cần sao chép dữ liệu khóa. Nó bù đắp cho điều này bằng cách tra cứu nhanh hơn. Tất nhiên, hai người có khả năng khác nhau nên phần lớn thời gian, việc xác định này nên dựa vào các yếu tố khác.


Mặc dù về mặt lý thuyết, điều này có thể trả lời câu hỏi, nhưng tốt hơn hết bạn nên đưa các phần thiết yếu của câu trả lời vào đây và cung cấp liên kết để tham khảo.
Tunaki

2

Bạn thường sẽ sử dụng Bộ khi tốc độ truy cập là quan trọng và thứ tự không quan trọng hoặc được xác định bằng các phương tiện khác (thông qua một vị từ hoặc bộ mô tả sắp xếp). Ví dụ: Core Data sử dụng các tập hợp khi các đối tượng được quản lý được truy cập thông qua mối quan hệ nhiều


1

Chỉ để thêm một chút nó, đôi khi tôi sử dụng set chỉ để xóa các bản sao khỏi mảng như: -

NSMutableSet *set=[[NSMutableSet alloc]initWithArray:duplicateValueArray]; // will remove all the duplicate values
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.