Bạn có thể giải thích sự khác biệt giữa HashSet<T>
và List<T>
trong .NET là gì không?
Có lẽ bạn có thể giải thích với một ví dụ trong trường hợp nào HashSet<T>
nên được ưu tiên chống lại List<T>
?
Bạn có thể giải thích sự khác biệt giữa HashSet<T>
và List<T>
trong .NET là gì không?
Có lẽ bạn có thể giải thích với một ví dụ trong trường hợp nào HashSet<T>
nên được ưu tiên chống lại List<T>
?
Câu trả lời:
Không giống như Danh sách <> ...
Hashset là một danh sách không có thành viên trùng lặp.
Do Hashset bị hạn chế chỉ chứa các mục duy nhất, nên cấu trúc bên trong được tối ưu hóa để tìm kiếm (so với danh sách) - nó nhanh hơn đáng kể
Thêm vào Hashset trả về boolean - false nếu bổ sung không thành công do đã tồn tại trong Set
Có thể thực hiện các hoạt động tập hợp toán học đối với Tập hợp: Liên kết / Giao lộ / IsSubsetOf, v.v.
Hashset không triển khai ICollection chỉ IList
Bạn không thể sử dụng các chỉ mục với Hashset, chỉ liệt kê.
Lý do chính để sử dụng Hashset sẽ là nếu bạn quan tâm đến việc thực hiện các thao tác Set.
Cho 2 bộ: hashIn1 và hashSet2
//returns a list of distinct items in both sets
HashSet set3 = set1.Union( set2 );
bay so với một hoạt động tương đương bằng cách sử dụng LINQ. Nó cũng gọn gàng hơn để viết!
Union
phương pháp. Tôi đã sử dụng UnionWith
thay thế.
Để chính xác hơn, hãy chứng minh bằng các ví dụ,
Bạn không thể sử dụng Hashset như trong ví dụ sau.
HashSet<string> hashSet1 = new HashSet<string>(){"1","2","3"};
for (int i = 0; i < hashSet1.Count; i++)
Console.WriteLine(hashSet1[i]);
hashSet1[i]
sẽ tạo ra một lỗi:
Không thể áp dụng lập chỉ mục với [] cho một biểu thức loại 'System.Collections.Generic.Hashset'
Bạn có thể sử dụng câu lệnh foreach:
foreach (var item in hashSet1)
Console.WriteLine(item);
Bạn không thể thêm các mục trùng lặp vào Hashset trong khi Danh sách cho phép bạn thực hiện việc này và trong khi bạn thêm một mục vào Hashset, bạn có thể kiểm tra xem nó có chứa mục đó hay không.
HashSet<string> hashSet1 = new HashSet<string>(){"1","2","3"};
if (hashSet1.Add("1"))
Console.WriteLine("'1' is successfully added to hashSet1!");
else
Console.WriteLine("'1' could not be added to hashSet1, because it contains '1'");
HashSet có một số chức năng hữu ích như IntersectWith
, UnionWith
, IsProperSubsetOf
, ExceptWith
, SymmetricExceptWith
, vv
IsProperSubsetOf
:
HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "4" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" };
HashSet<string> hashSet3 = new HashSet<string>() { "1", "2", "3", "4", "5" };
if (hashSet1.IsProperSubsetOf(hashSet3))
Console.WriteLine("hashSet3 contains all elements of hashSet1.");
if (!hashSet1.IsProperSubsetOf(hashSet2))
Console.WriteLine("hashSet2 does not contains all elements of hashSet1.");
UnionWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "3", "4" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" };
hashSet1.UnionWith(hashSet2); //hashSet1 -> 3, 2, 4, 6, 8
IntersectWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "3", "4", "8" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" }
hashSet1.IntersectWith(hashSet2);//hashSet1 -> 4, 8
ExceptWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "5", "6" };
HashSet<string> hashSet2 = new HashSet<string>() { "1", "2", "3", "4" };
hashSet1.ExceptWith(hashSet2);//hashSet1 -> 5, 6
SymmetricExceptWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "5", "6" };
HashSet<string> hashSet2 = new HashSet<string>() { "1", "2", "3", "4" };
hashSet1.SymmetricExceptWith(hashSet2);//hashSet1 -> 4, 5, 6
Nhân tiện, thứ tự không được bảo tồn trong HashSets. Trong ví dụ, chúng tôi đã thêm phần tử "2" cuối cùng nhưng nó theo thứ tự thứ hai:
HashSet<string> hashSet1 = new HashSet<string>() { "3", "4", "8" };
hashSet1.Add("1"); // 3, 4, 8, 1
hashSet1.Remove("4"); // 3, 8, 1
hashSet1.Add("2"); // 3, 2 ,8, 1
A HashSet<T>
là một lớp được thiết kế để cung cấp cho bạn O(1)
tra cứu ngăn chặn (nghĩa là bộ sưu tập này có chứa một đối tượng cụ thể không và cho tôi biết câu trả lời nhanh).
A List<T>
là một lớp được thiết kế để cung cấp cho bạn một bộ sưu tập với O(1)
quyền truy cập ngẫu nhiên hơn là có thể phát triển linh hoạt (nghĩ mảng động). Bạn có thể kiểm tra ngăn chặn O(n)
kịp thời (trừ khi danh sách được sắp xếp, sau đó bạn có thể thực hiện tìm kiếm nhị phân O(log n)
kịp thời).
Có lẽ bạn có thể giải thích với một ví dụ trong trường hợp nào
HashSet<T>
nên ưu tiên chống lạiList<T>
Khi bạn muốn kiểm tra ngăn chặn trong O(1)
.
Sử dụng List<T>
khi bạn muốn:
Nếu bạn biết chỉ số của mục bạn muốn (chứ không phải giá trị của chính mục đó), truy xuất là O(1)
. Nếu bạn không biết chỉ mục, việc tìm kiếm mục sẽ mất nhiều thời gian hơn O(n)
cho bộ sưu tập chưa được sắp xếp.
Sử dụng Hashset<T>
khi bạn muốn:
Nếu bạn biết tên của thứ bạn muốn tìm, Tra cứu là O(1)
(đó là phần 'Hash'). Nó không duy trì một thứ tự như thế List<T>
và bạn không thể lưu trữ các bản sao (thêm một bản sao không có tác dụng, đó là phần 'Đặt').
Một ví dụ về thời điểm sử dụng Hashset<T>
sẽ là nếu bạn muốn tìm hiểu xem một từ được chơi trong trò chơi Scrabble có phải là một từ hợp lệ trong tiếng Anh (hoặc ngôn ngữ khác) hay không. Thậm chí sẽ tốt hơn nếu bạn muốn xây dựng một dịch vụ web được sử dụng bởi tất cả các phiên bản trực tuyến của một trò chơi như vậy.
A List<T>
sẽ là một cấu trúc dữ liệu tốt để tạo bảng điểm để theo dõi điểm của người chơi.
Danh sách là một danh sách theo thứ tự. Nó là
Hashset là một bộ. Nó:
Danh sách phù hợp hơn khi bạn muốn truy cập bộ sưu tập của mình như thể nó giống như một mảng mà bạn có thể chắp thêm, chèn và xóa các mục. Hashset là lựa chọn tốt hơn nếu bạn muốn coi bộ sưu tập của mình như một "túi" các mặt hàng trong đó thứ tự không quan trọng hoặc khi bạn muốn so sánh nó với các bộ khác bằng các thao tác như IntersectWith hoặc UnionWith.
Danh sách không nhất thiết là duy nhất, trong khi hashset là cho một.
Danh sách là một tập hợp các đối tượng của Loại T không theo thứ tự, không giống như một mảng bạn có thể thêm và xóa các mục.
Bạn sẽ sử dụng một danh sách mà bạn muốn tham chiếu các thành viên theo thứ tự bạn đã lưu trữ chúng và bạn đang truy cập chúng theo một vị trí chứ không phải chính mục đó.
Hashset giống như một cuốn từ điển mà chính vật phẩm là chìa khóa cũng như giá trị, việc đặt hàng không được đảm bảo.
Bạn sẽ sử dụng Hashset nơi bạn muốn kiểm tra xem một đối tượng có trong bộ sưu tập không
List
duy trì một trật tự (tức là khi mọi thứ được thêm vào), nhưng không tự động sắp xếp các mục. Bạn sẽ phải gọi .Sort
hoặc sử dụng một SortedList
.
Nếu bạn quyết định áp dụng các cấu trúc dữ liệu này vào việc sử dụng thực tế trong phát triển dựa trên dữ liệu, Hashset rất hữu ích trong việc kiểm tra sao chép đối với các nguồn của bộ điều hợp dữ liệu, để làm sạch và di chuyển dữ liệu.
Ngoài ra, nếu sử dụng Lớp DataAnnotations, người ta có thể triển khai Logic khóa trên các thuộc tính của lớp và kiểm soát hiệu quả Chỉ mục tự nhiên (được nhóm hoặc không) với Hashset, trong đó việc này sẽ rất khó khăn trong việc triển khai Danh sách.
Tùy chọn mạnh mẽ để sử dụng danh sách là triển khai các tổng quát cho nhiều phương tiện trên Mô hình Chế độ xem, chẳng hạn như gửi danh sách các lớp tới Chế độ xem MVC cho Trình trợ giúp DropDownList và cũng để gửi dưới dạng cấu trúc JSON qua WebApi. Danh sách này cho phép logic tập hợp lớp điển hình và giữ tính linh hoạt cho cách tiếp cận "Giao diện" hơn như tính toán một mô hình khung nhìn duy nhất cho các phương tiện khác nhau.