ความแตกต่างระหว่าง HashSet <T> และ List <T> คืออะไร?


156

คุณช่วยอธิบายว่าอะไรคือความแตกต่างระหว่างHashSet<T>และList<T>ใน. NET

บางทีคุณอาจจะสามารถอธิบายได้ด้วยเช่นในกรณีสิ่งHashSet<T>ควรได้รับการแนะนำกับList<T>?



ผมขอแนะนำให้คุณปรึกษาบทความวิกิพีเดียen.wikipedia.org/wiki/Hash_tableและen.wikipedia.org/wiki/Dynamic_array
mqp

สำหรับประสิทธิภาพที่เกี่ยวข้องดูhashset-vs-list-performance
nawfal

คำตอบ:


213

ไม่เหมือนรายการ <> ...

  1. HashSet เป็นรายการที่ไม่มีสมาชิกที่ซ้ำกัน

  2. เนื่องจาก HashSet ถูก จำกัด ให้มีเฉพาะรายการที่ไม่ซ้ำกันดังนั้นโครงสร้างภายในจึงเหมาะสำหรับการค้นหา (เปรียบเทียบกับรายการ) - เร็วกว่ามาก

  3. การเพิ่ม HashSet จะส่งคืนบูลีน - false หากการเพิ่มล้มเหลวเนื่องจากมีอยู่แล้วในชุด

  4. สามารถดำเนินการชุดทางคณิตศาสตร์กับชุด: ยูเนี่ยน / แยก / IsSubsetOf ฯลฯ

  5. HashSet ไม่ได้ติดตั้ง ICistlection ของ IList เท่านั้น

  6. คุณไม่สามารถใช้ดัชนีที่มี HashSet เฉพาะตัวแจงนับ

เหตุผลหลักในการใช้ HashSet คือหากคุณสนใจที่จะทำการตั้งค่า

ให้ 2 ชุด: hashSet1 และ hashSet2

 //returns a list of distinct items in both sets
 HashSet set3 = set1.Union( set2 );

เปรียบเทียบกับการปฏิบัติการที่เทียบเท่าโดยใช้ LINQ นอกจากนี้ยังเป็น neater ที่จะเขียน!


IDK ฉันมีปัญหากับUnionวิธีการ ฉันใช้UnionWithแทน
ผู้ใช้

2
+1 สำหรับ "เหตุผลหลักในการใช้ HashedSet คือถ้าคุณสนใจที่จะทำการตั้งค่า"
LCJ

12
ที่จริงแล้วฉันชอบคำตอบที่ชี้ให้เห็นว่า HashSets เหมาะสมในกรณีที่คุณสามารถปฏิบัติต่อคอลเลกชันของคุณเป็น "รายการกระเป๋า" การตั้งค่าไม่บ่อยนักเช่นการตรวจสอบการบรรจุ ณ จุดใดก็ตามที่คุณมีชุดของรายการที่ไม่ซ้ำกัน (เช่นรหัส) และคุณจำเป็นต้องตรวจสอบการบรรจุ HashSet นั้นมีประโยชน์
ThunderGr

คำตอบที่ดี. ฉันถูกล่อลวงให้เพิ่มความแตกต่างของประสิทธิภาพการทำงานด้วย
nawfal

1
คำถาม: เหตุผลหลักคือการไม่มั่นใจว่าไม่มีรายการที่ซ้ำกันหรือไม่
Andrea Scarafoni

54

เพื่อให้แม่นยำยิ่งขึ้นให้แสดงด้วยตัวอย่าง

คุณไม่สามารถใช้ HashSet เหมือนในตัวอย่างต่อไปนี้

HashSet<string> hashSet1 = new HashSet<string>(){"1","2","3"};
for (int i = 0; i < hashSet1.Count; i++)
    Console.WriteLine(hashSet1[i]);

hashSet1[i] จะทำให้เกิดข้อผิดพลาด:

ไม่สามารถใช้การจัดทำดัชนีด้วย [] กับนิพจน์ประเภท 'System.Collections.Generic.HashSet'

คุณสามารถใช้คำสั่ง foreach:

foreach (var item in hashSet1)
    Console.WriteLine(item);

คุณไม่สามารถเพิ่มไอเท็มที่ซ้ำกันลงใน HashSet ได้ในขณะที่ลิสต์อนุญาตให้คุณทำสิ่งนี้และในขณะที่คุณเพิ่มไอเท็มไปยัง HashSet คุณสามารถตรวจสอบว่ามันมีรายการอยู่หรือไม่

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 มีฟังก์ชั่นที่มีประโยชน์บางอย่างเช่นIntersectWith, UnionWith, IsProperSubsetOf, ExceptWith, SymmetricExceptWithฯลฯ

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

โดยวิธีการสั่งซื้อจะไม่ถูกเก็บไว้ใน HashSets ในตัวอย่างเราเพิ่มองค์ประกอบ "2" สุดท้าย แต่อยู่ในลำดับที่สอง:

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

51

A HashSet<T>เป็นคลาสที่ออกแบบมาเพื่อให้คุณO(1)ค้นหาการบรรจุ (เช่นการสะสมนี้มีวัตถุเฉพาะและบอกคำตอบอย่างรวดเร็ว)

A List<T>เป็นคลาสที่ออกแบบมาเพื่อให้คอลเลกชันที่มีO(1)การเข้าถึงแบบสุ่มมากกว่าที่จะเติบโตแบบไดนามิก (คิดว่าอาร์เรย์แบบไดนามิก) คุณสามารถทดสอบการบรรจุได้O(n)ทันเวลา (ยกเว้นกรณีที่มีการเรียงลำดับรายการจากนั้นคุณสามารถทำการค้นหาแบบไบนารีได้O(log n)ทันเวลา)

บางทีคุณสามารถอธิบายด้วยตัวอย่างในกรณีที่HashSet<T>ควรได้รับการพิจารณาList<T>

O(1)เมื่อคุณต้องการที่จะทดสอบการบรรจุใน


ยกเว้นว่าเป็น O (บันทึก n) หากรายการเรียงลำดับ มันเร็วกว่าการค้นหาในรายการที่ไม่เรียงลำดับ
Andrei

20

ใช้List<T>เมื่อคุณต้องการ:

  • เก็บสะสมรายการในลำดับที่แน่นอน

ถ้าคุณรู้ว่าดัชนีของรายการที่คุณต้องการ (มากกว่าค่าของรายการตัวเอง) O(1)คือการดึง หากคุณไม่รู้จักดัชนีการค้นหารายการนั้นต้องใช้เวลานานกว่าO(n)สำหรับการรวบรวมที่ไม่เรียงลำดับ

ใช้Hashset<T>เมื่อคุณต้องการ:

  • ค้นหาอย่างรวดเร็วหากมีวัตถุบางอย่างอยู่ในคอลเลกชัน

หากคุณรู้ชื่อของสิ่งที่คุณต้องการค้นหาการค้นหาคือO(1)(นั่นคือส่วน 'แฮช') มันไม่ได้รักษาลำดับเช่นเดียวกับที่List<T>ทำและคุณไม่สามารถจัดเก็บรายการที่ซ้ำกัน (การเพิ่มรายการที่ซ้ำกันไม่มีผลนั่นคือส่วน 'ชุด')

ตัวอย่างของการใช้ a Hashset<T>จะเป็นถ้าคุณต้องการทราบว่าคำที่เล่นในเกม Scrabble เป็นคำที่ถูกต้องในภาษาอังกฤษ (หรือภาษาอื่น ๆ ) ยิ่งไปกว่านั้นถ้าคุณต้องการสร้างบริการบนเว็บที่จะใช้โดยอินสแตนซ์ทั้งหมดของเกมดังกล่าว

A List<T>จะเป็นโครงสร้างข้อมูลที่ดีสำหรับการสร้างกระดานคะแนนเพื่อติดตามคะแนนผู้เล่น


15

รายการคือรายการสั่งซื้อ มันคือ

  • เข้าถึงได้โดยดัชนีจำนวนเต็ม
  • สามารถมีรายการที่ซ้ำกัน
  • มีคำสั่งที่คาดการณ์ได้

HashSet เป็นชุด มัน:

  • สามารถบล็อกรายการที่ซ้ำกัน (ดูเพิ่ม (T) )
  • ไม่รับประกันการสั่งซื้อสินค้าภายในชุด
  • มีการดำเนินการที่คุณคาดหวังในชุดเช่น IntersectWith, IsProperSubsetOf, UnionWith

รายการมีความเหมาะสมมากกว่าเมื่อคุณต้องการเข้าถึงคอลเลกชันของคุณราวกับว่ามันเป็นเหมือนอาร์เรย์ที่คุณสามารถต่อเติมแทรกและลบรายการได้ HashSet เป็นตัวเลือกที่ดีกว่าถ้าคุณต้องการที่จะปฏิบัติต่อคอลเลกชันของคุณเช่น "กระเป๋า" ของรายการที่คำสั่งไม่สำคัญหรือเมื่อคุณต้องการเปรียบเทียบกับชุดอื่น ๆ โดยใช้การดำเนินการเช่น IntersectWith หรือ UnionWith



3

รายการคือชุดของวัตถุประเภท T ที่เรียงตามลำดับซึ่งแตกต่างจากอาร์เรย์คุณสามารถเพิ่มและลบรายการได้

คุณจะใช้รายการที่คุณต้องการอ้างอิงสมาชิกตามลำดับที่คุณเก็บไว้และคุณกำลังเข้าถึงพวกเขาตามตำแหน่งแทนที่จะเป็นรายการ

HashSet เป็นเหมือนพจนานุกรมที่ไอเท็มนั้นเป็นกุญแจสำคัญเช่นเดียวกับค่าการสั่งซื้อนั้นไม่รับประกัน

คุณจะใช้ HashSet ที่คุณต้องการตรวจสอบว่าวัตถุอยู่ในคอลเลกชัน


1
เพื่อชี้แจงในกรณีที่คนอื่นอ่านผิดในครั้งแรก - Listรักษาคำสั่งซื้อ (เช่นเมื่อมีการเพิ่มสิ่งต่าง ๆ ) แต่จะไม่เรียงลำดับรายการโดยอัตโนมัติ คุณจะต้องโทรหรือการใช้งาน.Sort SortedList
drzaus

1

หากคุณตัดสินใจที่จะใช้โครงสร้างข้อมูลเหล่านี้กับการใช้งานจริงในการพัฒนาที่ขับเคลื่อนด้วยข้อมูล HashSet มีประโยชน์อย่างมากในการทดสอบการจำลองแบบกับแหล่งข้อมูลอะแดปเตอร์สำหรับการล้างข้อมูลและการย้ายข้อมูล

นอกจากนี้หากใช้ DataAnnotations Class เราสามารถใช้ตรรกะของคีย์ในคุณสมบัติคลาสและควบคุมดัชนีธรรมชาติ (คลัสเตอร์หรือไม่) ได้อย่างมีประสิทธิภาพด้วย HashSet ซึ่งจะเป็นเรื่องยากมากในการใช้งานรายการ

ตัวเลือกที่รัดกุมสำหรับการใช้รายการคือการใช้งาน generics สำหรับหลาย ๆ สื่อบน View Model เช่นการส่งรายการของคลาสไปยัง MVC View สำหรับ DropDownList Helper และสำหรับส่งเป็นโครงสร้าง JSON ผ่าน WebApi รายการนี้ช่วยให้ตรรกะการรวบรวมคลาสทั่วไปและมีความยืดหยุ่นสำหรับ "ส่วนต่อประสาน" มากกว่าเช่นวิธีการคำนวณรูปแบบมุมมองเดียวไปยังสื่อที่แตกต่างกัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.