ทุกอย่างเกี่ยวกับโครงสร้างข้อมูลที่กำหนดใน JavaScript
มีหลายสถานการณ์ที่คุณต้องเปรียบเทียบหลายรายการและแยกรายการที่พวกเขามีหรือไม่เหมือนกัน ใช้ได้ในรายการเดียวเท่านั้น เป็นต้น ชุดต่างๆ ช่วยให้คุณสามารถทำสิ่งนั้นได้และอื่นๆ อีกมากมาย โดยเฉพาะอย่างยิ่งชุด Javascript นั้นเป็นชุดที่พิเศษและทรงพลังมาก แต่ก็ยังขาดสิ่งสำคัญที่ภาษาอื่นนำเสนอ
เวอร์ชันวิดีโอของบทความนี้
โพสต์นี้เป็นเวอร์ชันบทความที่ได้รับการปรับปรุงและมีรายละเอียดมากขึ้นของ "Set Data Structure Series" บน Youtube ซึ่งคุณสามารถตรวจสอบได้ว่าคุณชอบวิดีโอหรือไม่
ชุดคืออะไร?
Set คือคอลเลกชันคีย์ของรายการที่ไม่ซ้ำกันซึ่งจัดเก็บโดยไม่มีลำดับใดโดยเฉพาะ ต่างจากคอลเลกชันประเภทอื่น ๆ เช่น "สแต็ค", "คิว" และ "อาร์เรย์" ชุดใช้ในการเปรียบเทียบรายการและเพื่อทดสอบว่ามีรายการอยู่ในชุดหรือไม่ ถูกต้องที่จะบอกว่า Set เก็บคู่คีย์-คีย์ค่าเนื่องจากคุณใช้ไอเท็มเพื่อทดสอบว่าอยู่ในเซ็ตหรือไม่
Set ยังเป็นประเภทข้อมูลเชิงนามธรรม ซึ่งหมายความว่าถูกกำหนดโดยพฤติกรรมของมันเหมือนกับโครงสร้างข้อมูล Stack และ Queue เนื่องจากลักษณะของคีย์-คีย์ ชุดจึงมีความเกี่ยวข้องอย่างใกล้ชิดกับแผนที่มากกว่าสิ่งอื่นใด และคุณยังสามารถใช้งานชุดโดยใช้ชุดนั้นได้
ชุดจาวาสคริปต์
ชุด Javascript เป็นพื้นฐานและเรียบง่ายมาก ไม่มีความสามารถในการดำเนินการตั้งค่าทั่วไปที่ภาษาอื่นๆ มักจะมีให้ นอกจากนี้ยังใช้อัลกอริธึมเฉพาะเพื่อทดสอบว่ารายการเหมือนกันหรือไม่เมื่อเปรียบเทียบกับการตรวจสอบที่เข้มงวดแบบสามเท่า (===)
ซึ่งหมายความว่าการจัดเก็บ “unknown”, “null” และ “NaN” ในชุดจะรับประกันว่าจะมีอยู่เพียงครั้งเดียว แม้ว่า “Nan ! == น่าน”. สิ่งที่โดดเด่นคือการจัดเก็บประเภทวัตถุที่ตรวจสอบความเท่าเทียมกันได้ยาก
const set = new Set([null, undefined, null, NaN, NaN, null]); console.log([...set]); // [null, undefined, NaN]
คุณแทรกด้วย “เพิ่ม” และลบด้วย “ลบ” สำหรับรายการเดียวหรือทั้งชุดด้วย “ล้าง” วิธีการ สามารถทำซ้ำได้และมาพร้อมกับตัววนซ้ำสำหรับ "ค่า" และ "รายการ" เนื่องจากคีย์และค่าเหมือนกัน ดังนั้นความจริงที่ว่ามันมักถูกอธิบายว่าเป็นชุดของคู่คีย์-คีย์ค่า นอกจากนี้ยังเปิดเผยวิธีการ “forEach” เช่น Array และ Map ว่าเป็นวิธีที่เร็วกว่าในการวนซ้ำรายการต่างๆ
const set = new Set([78, 20, 44]); set.add(12); set.delete(78); set.clear();
ตามที่กล่าวไว้ก่อนหน้านี้ Set ใช้ในการเปรียบเทียบและตรวจสอบรายการ แต่วิธีเดียวที่ช่วยให้คุณตรวจสอบบางสิ่งบางอย่างได้คือวิธี “has” ซึ่งกำหนดรายการให้ มันจะคืนค่าจริงหรือเท็จ ไม่ว่าจะอยู่ในชุดหรือไม่ก็ตาม
set.has(12); // true set.has(21); // false
หากต้องการทำการตรวจสอบที่ซับซ้อนมากขึ้น คุณต้องเพิ่มวิธีการใหม่ ๆ ซึ่งจะทำให้คุณสามารถเปรียบเทียบได้อย่างมีประสิทธิภาพและทำงานกับข้อมูลรายการได้อย่างดี ซึ่งฉันจะแสดงให้คุณเห็นในภายหลัง
ตั้งค่าเทียบกับอาร์เรย์
Set นั้นแตกต่างจาก Array หลายไมล์ และเหตุผลที่พวกเขามักจะเปรียบเทียบกันใน Javascript ก็คือ Array มักจะถูกใช้เพื่อทำสิ่งต่าง ๆ ที่ Set ทำ
อาร์เรย์จัดเก็บรายการตามลำดับดัชนีและอนุญาตให้อ่านและเขียนรายการได้อย่างรวดเร็วตราบใดที่คุณทราบดัชนีของรายการเหล่านั้น ชุดอนุญาตสิ่งเดียวกันตราบเท่าที่คุณมีรายการ นี่แสดงว่า Array คือคอลเลกชันของรายการตามดัชนี และ Set คือคอลเลกชันของรายการตามคีย์
อาร์เรย์มีไว้เพื่อใช้เมื่อคุณต้องการเก็บรายการไว้ในลำดับที่แน่นอนสำหรับการเข้าถึงและการจัดการ ในชุด ไอเท็มจะไม่ซ้ำกันแต่สามารถทำซ้ำภายในอาร์เรย์ได้ Set มักใช้เพื่อล้างรายการอาร์เรย์ที่ซ้ำกัน แต่ไม่ได้มีไว้สำหรับสิ่งที่ Array มีไว้
const array = [23, 41, 12, 41, 67, 23]; const noRepeatArray = Array.from(new Set(array)); // becomes [23, 41, 12, 67] learn more about Array
Set ไม่ได้และไม่ได้หมายถึงการแทนที่ Array เน้นเพียงปัญหาเฉพาะของการเปรียบเทียบรายการและการตรวจสอบรายการที่ Array ไม่ดีหากไม่มีโค้ดเพิ่มเติมมากมายสำหรับการจัดการ
const array = [12, 45]; const set = new Set([12, 45]); // extra code needed to ensure uniqueness if(!array.includes(12)) { array.push(12); } // does nothing since it already exists set.add(12); // slower: checks every item if necessary array.includes(45); // faster: since it checks the key set.has(45);
ควรใช้ชุดเมื่อใด?
คุณใช้ Set เมื่อสิ่งที่คุณต้องการคือทำการเปรียบเทียบและตรวจสอบรายการเฉพาะ สมมติว่าคุณมีรายการ A และ B และต้องการทราบว่าเหมือนกันหรือไม่ รายการใดที่ A มี แต่ B ไม่มี หรือรายการใดบ้างที่มีเหมือนกัน นอกจากนี้ ไอเทมเซ็ตยังมีเอกลักษณ์เฉพาะตัวและเป็นคุณสมบัติที่ดีเยี่ยมในการใช้ประโยชน์
คุณใช้มันเพื่อเก็บรายการที่ไม่ซ้ำกันไว้เพื่อทำซ้ำในภายหลังและทำสิ่งต่างๆ เพื่อให้คุณไม่ต้องกังวลว่ารายการจะมีรายการซ้ำกัน คุณใช้มันเพื่อเมื่อคุณมีรายการตัวอย่างอื่น คุณจะสามารถค้นหาว่ารายการตัวอย่างเหล่านั้นแตกต่างกันหรือจับคู่กันอย่างไรเพื่อประกอบการตัดสินใจ คุณใช้มันเพื่อที่จะสามารถเปลี่ยนเป็น Array ในภายหลังเพื่อดำเนินการเหมือนอาเรย์ได้มากขึ้นและในทางกลับกัน
ตั้งค่าการดำเนินการ
ในทางคณิตศาสตร์ เมื่อใดก็ตามที่คุณพูดถึงเซต คุณสามารถดำเนินการต่างๆ ได้ ตามความเป็นจริง Set คือการใช้คอมพิวเตอร์ของเซตจำกัดทางคณิตศาสตร์
ในการแสดงการตั้งค่าการดำเนินการในโค้ดอย่างถูกต้อง ให้ขยายชุด Javascript เพื่อสืบทอดคุณสมบัติและวิธีการของมัน และกำหนดวิธีการที่จำเป็นเพิ่มเติมให้กับมัน สำหรับโค้ดด้านล่าง เราต้องการเพียงวิธีเดียวที่จะตรวจสอบว่าชุดที่ถูกต้องมีให้หรือไม่ สำหรับตัวอย่างนี้ ชุดที่ถูกต้องต้องเป็นอินสแตนซ์ของวัตถุชุดและไม่ว่างเปล่า
class SetExtended extends Set { #isValidSet = (set) => { return set && set instanceof Set && set.size > 0; }; }
- ยูเนี่ยน:
การดำเนินการยูเนี่ยนจะรวมหลายชุดและส่งกลับผลลัพธ์ของการผสาน สำหรับการใช้งานโค้ดด้านล่างนี้ เราจะส่งคืนชุดใหม่โดยกระจายชุดปัจจุบันและชุดที่กำหนดในอาร์เรย์เพื่อสร้างชุดนั้น
union(set) { if (!this.#isValidSet(set)) return new SetExtended(); return new SetExtended([...this, ...set]); }
- จุดตัด:
การดำเนินการสกัดกั้นทำให้เรามีชุดใหม่ที่มีเฉพาะรายการที่มีเหมือนกัน ตัวอย่างด้านล่างครอบคลุมชุดที่เล็กกว่า (หลีกเลี่ยงการตรวจสอบที่ไม่จำเป็น) และตรวจสอบว่ามีรายการอยู่ในชุดที่ใหญ่กว่าหรือไม่ และเพิ่มไปยังชุดจุดตัด จากนั้นส่งคืนที่ส่วนท้าย
intersection(set) { const intersectionSet = new SetExtended(); if (!this.#isValidSet(set)) return intersectionSet; const [smallerSet, biggerSet] = set.size <= this.size ? [set, this] : [this, set]; smallerSet.forEach((item) => { if (biggerSet.has(item)) intersectionSet.add(item); }); return intersectionSet; }
- ความแตกต่าง:
การดำเนินการส่วนต่างจะส่งคืนชุดใหม่ที่มีเฉพาะรายการที่ชุดไม่มีเหมือนกัน เรียกอีกอย่างว่าการลบ การใช้งานด้านล่างครอบคลุมชุดปัจจุบันและรวบรวมรายการที่ไม่มีอยู่ในชุดอื่น ๆ ลงในชุดผลต่าง
difference(set) { if (!this.#isValidSet(set)) return new SetExtended(); const differenceSet = new SetExtended(); this.forEach((item) => { if (!set.has(item)) differenceSet.add(item); }); return differenceSet; }
- ผลต่างของทางแยก:
การดำเนินการผลต่างของทางแยกจะตรงกันข้ามกับทางแยก เรียกอีกอย่างว่า Exclusive หรือ มันจะส่งคืนชุดใหม่ที่มีรายการทั้งหมดที่ทั้งคู่ไม่มีเหมือนกัน และในการใช้งานด้านล่าง เราเพียงแค่สร้างชุดใหม่โดยมีความแตกต่างกัน
intersectionDifference(set) { if (!this.#isValidSet(set)) return new SetExtended(); return new SetExtended([ ...this.difference(set), ...set.difference(this), ]); }
- เซตย่อย:
เซตหนึ่งเรียกว่าเซตย่อยเมื่อรายการทั้งหมดถูกบรรจุโดยอีกชุดหนึ่ง การใช้งานด้านล่างจะตรวจสอบขนาดก่อนเนื่องจากชุดไม่สามารถเป็นชุดย่อยของชุดอื่นได้หากใหญ่กว่า จากนั้นสำหรับทุกรายการจะตรวจสอบว่ามีอยู่ในชุดอื่นหรือไม่
isSubsetOf(set) { if (!this.#isValidSet(set)) return false; return this.size <= set.size && [...this].every(item => set.has(item)) }
- ซูเปอร์เซ็ต:
ซูเปอร์เซ็ตอยู่ตรงข้ามกับเซ็ตย่อย ชุดคือชุดซุปเปอร์เซ็ตเมื่อมีรายการทั้งหมดของชุดขนาดที่เล็กกว่าหรือเท่ากันอีกชุดหนึ่ง
isSupersetOf(set) { if (!this.#isValidSet(set)) return false; return this.size >= set.size && [...set].every(item => this.has(item)) }
คุณไม่ได้จำกัดอยู่เพียงการดำเนินการเหล่านี้และมีอิสระที่จะรวมเพิ่มเติมเพื่อแก้ไขความต้องการประเภทที่คุณอาจมี โดยทั่วไป การตรวจสอบเหล่านี้ใช้งานง่ายสุด ๆ และคุณสามารถใช้ประโยชน์จากข้อเท็จจริงที่ว่า Set และ Array สามารถแปลงกลับไปและส่งต่อได้เสมอ เพื่อใช้ประโยชน์จากวิธีการของ Array ที่ทรงพลัง
ซอร์สโค้ด: ตรวจสอบนี้ โค้ดเต็มบน Github
ชุดคงที่
ชุดคงที่คือชุดที่ประกอบด้วยรายการต่างๆ ที่ถูกเตรียมใช้งานเสมอ คุณไม่สามารถเพิ่ม ลบ หรือล้างรายการได้ ชุด Javascript ไม่ใช่แบบคงที่และจะเปิดเผยวิธีการแก้ไขชุดเสมอหลังจากสร้างชุดแล้ว เพื่อให้ได้ชุดคงที่ เราต้องแทนที่พฤติกรรมนี้ในลักษณะเดียวกับที่เราขยายออกไป
วิธีที่ง่ายที่สุดคือการขยายและแทนที่วิธีที่แก้ไข ด้วยวิธีนี้ คุณจะไม่สามารถเปลี่ยนแปลงได้ในภายหลัง
class StaticSet extends SetExtended { constructor(items) { super(items); this.add = undefined; this.delete = undefined; this.clear = undefined; } }
บทสรุป
โดยทั่วไป หากคุณพบว่าตัวเองมักจะตรวจสอบรายการที่มีอยู่ในรายการและกรองรายการสำหรับบางส่วนของรายการ นั่นเป็นสัญญาณที่ชัดเจนที่คุณควรสำรวจชุดต่างๆ ชุด Javascript นั้นทรงพลังมากและใช้งานง่ายและอาจประเมินค่าต่ำเกินไป
ตรวจสอบ "ก่อนบล็อกอัฒภาค" เพื่อดูบทความโครงสร้างข้อมูลเพิ่มเติมเช่นนี้ นอกจากนี้ ให้ตรวจสอบ "บทความโครงสร้างข้อมูลอาร์เรย์" เพื่อดูรายละเอียดเพิ่มเติม
ช่อง YouTube: ก่อนอัฒภาค
เว็บไซต์: beforesemicolon.com
เนื้อหาเพิ่มเติมได้ที่ plainenglish.io