ทุกอย่างเกี่ยวกับโครงสร้างข้อมูลที่กำหนดใน 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