ฉันกำลังสำรวจHashSet<T>ประเภท แต่ฉันไม่เข้าใจว่ามันอยู่ที่ใดในคอลเล็กชัน
สามารถใช้แทน a List<T>? ฉันจินตนาการว่าประสิทธิภาพของ a HashSet<T>จะดีขึ้น แต่ฉันไม่เห็นการเข้าถึงองค์ประกอบของแต่ละบุคคล
เป็นเพียงการแจงนับเท่านั้น?
ฉันกำลังสำรวจHashSet<T>ประเภท แต่ฉันไม่เข้าใจว่ามันอยู่ที่ใดในคอลเล็กชัน
สามารถใช้แทน a List<T>? ฉันจินตนาการว่าประสิทธิภาพของ a HashSet<T>จะดีขึ้น แต่ฉันไม่เห็นการเข้าถึงองค์ประกอบของแต่ละบุคคล
เป็นเพียงการแจงนับเท่านั้น?
คำตอบ:
สิ่งที่สำคัญเกี่ยวกับการHashSet<T>มีสิทธิในชื่อ: มันเป็นชุด สิ่งเดียวที่คุณสามารถทำได้ในชุดเดียวคือการกำหนดว่าสมาชิกคืออะไรและตรวจสอบว่ารายการนั้นเป็นสมาชิกหรือไม่
การถามว่าคุณสามารถดึงองค์ประกอบเดียวได้หรือไม่ (เช่นset[45]) เป็นการเข้าใจแนวคิดของชุดนั้นผิด ไม่มีสิ่งที่เรียกว่าองค์ประกอบที่ 45 ของเซต สินค้าในชุดไม่มีการสั่งซื้อ ชุด {1, 2, 3} และ {2, 3, 1} เหมือนกันทุกประการเนื่องจากมีสมาชิกภาพเหมือนกันและการเป็นสมาชิกก็สำคัญ
มันค่อนข้างอันตรายที่จะทำซ้ำHashSet<T>เนื่องจากการทำเช่นนั้นจะทำให้เกิดการสั่งซื้อสินค้าในชุด คำสั่งนั้นไม่ได้เป็นสมบัติของชุด คุณไม่ควรพึ่งพามัน หากการสั่งซื้อสินค้าในคอลเลกชันเป็นสิ่งสำคัญสำหรับคุณคอลเลกชันนั้นจะไม่ใช่ชุด
ชุดมีจำนวน จำกัด และมีสมาชิกที่ไม่ซ้ำใคร ในทางกลับกันมันเร็วมาก
HashSetไม่ได้กำหนดไว้ดังนั้นอย่าพึ่งพาคำสั่งของตัววนซ้ำ หากคุณทำซ้ำชุดนี้เนื่องจากคุณกำลังทำอะไรบางอย่างกับรายการในชุดสิ่งนั้นจะไม่เป็นอันตรายเว้นแต่คุณจะพึ่งพาสิ่งที่เกี่ยวข้องกับคำสั่งซื้อ A SortedSetมีคุณสมบัติทั้งหมดของคำสั่งHashSet บวกอย่างไรก็ตามSortedSetไม่ได้มาจากHashSet; จัดเรียงใหม่SortedSet คือชุดของวัตถุที่แตกต่างกันตามลำดับ
นี่คือตัวอย่างที่แท้จริงของสถานที่ที่ฉันใช้ a HashSet<string>:
ส่วนหนึ่งของการเน้นไวยากรณ์ของฉันสำหรับไฟล์ UnrealScript เป็นคุณลักษณะใหม่ที่ความคิดเห็นไฮไลท์ Doxygen สไตล์ ฉันจำเป็นต้องสามารถบอกได้ว่า a @หรือ\คำสั่งนั้นถูกต้องเพื่อพิจารณาว่าจะแสดงเป็นสีเทา (ถูกต้อง) หรือสีแดง (ไม่ถูกต้อง) ฉันมีHashSet<string>คำสั่งที่ถูกต้องทั้งหมดดังนั้นเมื่อใดก็ตามที่ฉันกด@xxxโทเค็นในตัวเล็กซ์ฉันจะใช้validCommands.Contains(tokenText)เป็นการตรวจสอบความถูกต้อง O (1) ของฉัน ฉันไม่สนใจอะไรเลยนอกจากการมีอยู่ของคำสั่งในชุดคำสั่งที่ถูกต้อง ลองดูทางเลือกอื่นที่ฉันเผชิญ:
Dictionary<string, ?>: ประเภทใดที่ฉันใช้สำหรับค่า? ContainsKeyค่าที่มีความหมายตั้งแต่ฉันแค่ไปกับการใช้งาน หมายเหตุ: ก่อนหน้า. NET 3.0 นี่เป็นทางเลือกเดียวสำหรับการค้นหา O (1) - HashSet<T>ถูกเพิ่มสำหรับ 3.0 และขยายเพื่อใช้งานISet<T>สำหรับ 4.0List<string>: ถ้าฉันจัดเรียงรายการไว้ฉันสามารถใช้ได้BinarySearchซึ่งก็คือ O (log n) (ไม่เห็นข้อเท็จจริงนี้ที่กล่าวถึงข้างต้น) อย่างไรก็ตามเนื่องจากรายการคำสั่งที่ถูกต้องของฉันเป็นรายการคงที่ที่ไม่เคยเปลี่ยนแปลงสิ่งนี้จะไม่เหมาะสมไปกว่า ...string[]: อีกครั้งArray.BinarySearchให้ประสิทธิภาพ O (log n) หากรายการสั้นนี่อาจเป็นตัวเลือกที่มีประสิทธิภาพดีที่สุด มันก็จะมีค่าใช้จ่ายน้อยกว่าพื้นที่HashSet, หรือDictionary Listถึงแม้BinarySearchจะไม่เร็วกว่าสำหรับชุดใหญ่ แต่สำหรับชุดเล็กก็ควรค่าแก่การทดลอง ของฉันมีหลายร้อยรายการดังนั้นฉันจึงส่งต่อไปHashSet<T>ดำเนินการICollection<T>อินเตอร์เฟซ:
public interface ICollection<T> : IEnumerable<T>, IEnumerable
{
// Methods
void Add(T item);
void Clear();
bool Contains(T item);
void CopyTo(T[] array, int arrayIndex);
bool Remove(T item);
// Properties
int Count { get; }
bool IsReadOnly { get; }
}
การList<T>ดำเนินการIList<T>ซึ่งขยายไฟล์ICollection<T>
public interface IList<T> : ICollection<T>
{
// Methods
int IndexOf(T item);
void Insert(int index, T item);
void RemoveAt(int index);
// Properties
T this[int index] { get; set; }
}
HashSet ได้กำหนดความหมายโดยใช้แฮชแท็กภายใน:
ชุดคือคอลเล็กชันที่ไม่มีองค์ประกอบที่ซ้ำกันและองค์ประกอบที่ไม่เรียงลำดับกัน
HashSet ได้รับอะไรบ้างหากสูญเสียพฤติกรรมดัชนี / ตำแหน่ง / รายการ
การเพิ่มและการดึงรายการจาก HashSet จะเกิดขึ้นโดยตัวออบเจ็กต์เองเสมอไม่ใช่ผ่านตัวสร้างดัชนีและใกล้เคียงกับการดำเนินการ O (1) (รายการคือ O (1) เพิ่ม, O (1) ดึงโดยดัชนี, O (n) ค้นหา / ลบ)
พฤติกรรมของ HashSet สามารถเปรียบเทียบได้กับการใช้ a Dictionary<TKey,TValue>โดยเพิ่ม / ลบคีย์เป็นค่าเท่านั้นและละเว้นค่าพจนานุกรมเอง คุณคาดว่าคีย์ในพจนานุกรมจะไม่มีค่าซ้ำกันและนั่นคือจุดสำคัญของส่วน "Set"
ประสิทธิภาพจะเป็นเหตุผลที่ไม่ดีในการเลือก HashSet over List สิ่งใดที่จับเจตนาของคุณได้ดีกว่ากัน? หากคำสั่งซื้อมีความสำคัญ Set (หรือ HashSet) จะไม่ทำงาน หากมีการอนุญาตให้ทำซ้ำได้เช่นเดียวกัน แต่มีหลายสถานการณ์ที่เราไม่สนใจคำสั่งซื้อและเราไม่อยากมีรายการที่ซ้ำกัน - และนั่นคือเวลาที่คุณต้องการ Set
Performance would be a bad reason to choose HashSet over List: ฉันไม่เห็นด้วยกับคุณ นั่นเป็นการบอกว่าการเลือก Dictionray แทนสองรายการไม่ได้ช่วยในการแสดง ดูบทความต่อไปนี้
string[].ContainsและHashSet<string>.Containsแสดงเจตนาของคุณได้ดีเท่า ๆ กัน เหตุผลในการเลือก HashSet ก็คือมันจะทำงานได้เร็วขึ้นมาก
HashSet เป็นชุดที่ดำเนินการโดยการแฮช ชุดคือชุดของค่าที่ไม่มีองค์ประกอบที่ซ้ำกัน โดยทั่วไปค่าในชุดจะไม่เรียงลำดับ ไม่จึงไม่สามารถใช้ชุดเพื่อแทนที่รายการได้ (เว้นแต่ว่าคุณควรใช้ชุดตั้งแต่แรก)
หากคุณสงสัยว่าชุดใดที่ดีสำหรับ: ทุกที่ที่คุณต้องการกำจัดรายการที่ซ้ำกันอย่างชัดเจน ตามตัวอย่างที่มีการปรับปรุงเล็กน้อยสมมติว่าคุณมีรายการซอฟต์แวร์ที่แก้ไขแล้ว 10.000 รายการและคุณต้องการทราบจำนวนคนที่มีส่วนร่วมในโครงการนั้น คุณสามารถใช้ a Set<string>และทำซ้ำในรายการการแก้ไขและเพิ่มผู้เขียนของการแก้ไขแต่ละคนในชุด เมื่อคุณทำซ้ำขนาดของชุดคือคำตอบที่คุณกำลังมองหา
HashSet จะถูกใช้เพื่อลบองค์ประกอบที่ซ้ำกันในคอลเลกชันที่ไม่สามารถคำนวณได้ของ IE ตัวอย่างเช่น,
List<string> duplicatedEnumrableStrings = new List<string> {"abc", "ghjr", "abc", "abc", "yre", "obm", "ghir", "qwrt", "abc", "vyeu"};
HashSet<string> uniqueStrings = new HashSet(duplicatedEnumrableStrings);
หลังจากรันโค้ดเหล่านั้นแล้ว uniqueStrings จะถือ {"abc", "ghjr", "yre", "obm", "qwrt", "vyeu"};
อาจใช้บ่อยที่สุดสำหรับแฮชเซ็ตคือการดูว่ามีองค์ประกอบบางอย่างหรือไม่ซึ่งใกล้เคียงกับการดำเนินการ O (1) สำหรับพวกเขา (สมมติว่ามีฟังก์ชันการแฮชที่แข็งแกร่งเพียงพอ) ซึ่งต่างจากรายการที่ตรวจสอบการรวมเป็น O ( n) (และชุดที่เรียงลำดับซึ่งเป็น O (log n)) ดังนั้นหากคุณทำการตรวจสอบเป็นจำนวนมากไม่ว่าจะมีรายการอยู่ในบางรายการหรือไม่ hahssets อาจช่วยเพิ่มประสิทธิภาพได้ หากคุณทำซ้ำเพียงครั้งเดียวจะไม่มีความแตกต่างมากนัก (การทำซ้ำทั้งชุดคือ O (n) เช่นเดียวกับรายการและแฮชเซ็ตจะมีค่าใช้จ่ายค่อนข้างมากกว่าเมื่อเพิ่มรายการ)
และไม่คุณไม่สามารถทำดัชนีชุดซึ่งจะไม่สมเหตุสมผลอยู่ดีเพราะชุดไม่ได้เรียงลำดับ หากคุณเพิ่มบางรายการชุดจะไม่จำว่ารายการใดเป็นรายการแรกและรายการที่สองเป็นต้น
HashSet<T>เป็นโครงสร้างข้อมูลในกรอบ. NET ที่สามารถแสดงชุดทางคณิตศาสตร์เป็นวัตถุ ในกรณีนี้จะใช้รหัสแฮช ( GetHashCodeผลลัพธ์ของแต่ละรายการ) เพื่อเปรียบเทียบความเท่าเทียมกันขององค์ประกอบชุด
ชุดแตกต่างจากรายการที่อนุญาตให้เกิดองค์ประกอบเดียวกันที่มีอยู่ภายในได้เพียงรายการเดียว HashSet<T>จะกลับมาfalseถ้าคุณพยายามเพิ่มองค์ประกอบที่สองที่เหมือนกัน อันที่จริงการค้นหาองค์ประกอบนั้นรวดเร็วมาก ( O(1)เวลา) เนื่องจากโครงสร้างข้อมูลภายในเป็นเพียงแฮชแท็ก
หากคุณสงสัยว่าควรใช้ตัวList<T>ไหนโปรดทราบว่าการใช้ตำแหน่งที่HashSet<T>เหมาะสมไม่ใช่ข้อผิดพลาดที่ใหญ่ที่สุดแม้ว่าอาจทำให้เกิดปัญหาที่คุณมีรายการซ้ำที่ไม่พึงปรารถนาในคอลเลกชันของคุณ ยิ่งไปกว่านั้นการค้นหา (การเรียกค้นรายการ) นั้นมีประสิทธิภาพมากกว่าอย่างมาก - O(1)ตามหลักการแล้ว (เพื่อการจัดเก็บข้อมูลที่สมบูรณ์แบบ) แทนที่จะเป็นO(n)เวลาซึ่งค่อนข้างสำคัญในหลาย ๆ สถานการณ์
List<T>ใช้เพื่อจัดเก็บชุดข้อมูลที่สั่งซื้อ หากคุณทราบลำดับสัมพัทธ์ขององค์ประกอบของรายการคุณสามารถเข้าถึงได้ในเวลาคงที่ อย่างไรก็ตามในการพิจารณาว่าองค์ประกอบอยู่ที่ใดในรายการหรือตรวจสอบว่ามีอยู่ในรายการหรือไม่เวลาในการค้นหาจะเป็นแบบเส้นตรง ในทางกลับกันHashedSet<T>ไม่รับประกันลำดับของข้อมูลที่จัดเก็บและส่งผลให้เวลาในการเข้าถึงองค์ประกอบคงที่
เป็นชื่อที่แสดงถึงHashedSet<T>เป็นโครงสร้างข้อมูลที่ดำเนินการกำหนดความหมาย โครงสร้างข้อมูลได้รับการปรับให้เหมาะสมเพื่อใช้การดำเนินการชุด (เช่น Union, Difference, Intersect) ซึ่งไม่สามารถทำได้อย่างมีประสิทธิภาพกับการใช้งาน List แบบเดิม
ดังนั้นในการเลือกประเภทข้อมูลที่จะใช้ขึ้นอยู่กับว่าคุณกำลังพยายามทำอะไรกับแอปพลิเคชันของคุณ หากคุณไม่สนใจเกี่ยวกับวิธีการที่องค์ประกอบของคุณจะได้รับคำสั่งในการเก็บรวบรวมและมีเพียงต้องการที่จะ enumarate หรือตรวจสอบสำหรับการดำรงอยู่, HashSet<T>การใช้งาน มิฉะนั้นให้พิจารณาใช้List<T>หรือโครงสร้างข้อมูลอื่นที่เหมาะสม
ในสถานการณ์จำลองพื้นฐานHashSet<T>ควรใช้เมื่อคุณต้องการการดำเนินการชุดที่เฉพาะเจาะจงมากขึ้นในสองคอลเลกชันมากกว่าที่ LINQ ให้ไว้ วิธีการ LINQ ชอบDistinct, Union, IntersectและExceptมีความเพียงพอในสถานการณ์ส่วนใหญ่ แต่บางครั้งคุณอาจจะต้องดำเนินงานเม็ดเล็กมากขึ้นและHashSet<T>ให้:
UnionWithIntersectWithExceptWithSymmetricExceptWithOverlapsIsSubsetOfIsProperSubsetOfIsSupersetOfIsProperSubsetOfSetEqualsความแตกต่างอีกอย่างระหว่างวิธีการ LINQ และHashSet<T>"การทับซ้อนกัน" คือ LINQ จะส่งคืนใหม่เสมอIEnumerable<T>และHashSet<T>วิธีการแก้ไขการรวบรวมแหล่งที่มา
ในระยะสั้น - เมื่อใดก็ตามที่คุณถูกล่อลวงให้ใช้พจนานุกรม (หรือพจนานุกรมโดยที่ S เป็นสมบัติของ T) คุณควรพิจารณา HashSet (หรือ HashSet + ที่ใช้ IEquatable บน T ซึ่งเท่ากับ S)
SortedSetโครงสร้างข้อมูลอาจขัดแย้งกับสิ่งที่คุณพูดเกี่ยวกับคำสั่งที่ไม่เป็นสมบัติของชุดหรือชี้ให้เห็นถึงความเข้าใจผิดจากทีมพัฒนา