Set / Map usage สำหรับผู้เริ่มต้น (JavaScript)
บทนี้จะพาเข้าใจ Set และ Map แบบใช้งานได้จริง ตั้งแต่ความหมาย, ความต่างกับ Object และ Array, การเชื่อมโยงกับแนวคิด Hashing, ไปจนถึงโจทย์ฝึกท้ายบทแบบลงมือทำใน Playground
1. Set คืออะไร
Set คือโครงสร้างข้อมูลที่เก็บค่าที่ไม่ซ้ำกัน (unique values) ถ้าพยายามเพิ่มค่าซ้ำเข้าไป ระบบจะไม่เพิ่มซ้ำให้
เหมาะมากกับงานประเภทตรวจข้อมูลซ้ำ, เก็บรายการที่เคยเจอ, และสร้างชุดข้อมูลที่ต้องการความเป็นเอกลักษณ์
2. Map คืออะไร
Map คือโครงสร้างข้อมูลที่เก็บข้อมูลแบบคู่ key-value โดย key หนึ่งตัวชี้ไปยัง value หนึ่งค่า เหมือนตารางจับคู่ข้อมูล
ใช้เมื่อเราต้องการเข้าถึงข้อมูลจาก key โดยตรง เช่น id ผู้ใช้ -> profile, รหัสสินค้า -> ชื่อสินค้า
3. ความต่างระหว่าง Set และ Map
Set
เก็บ "ค่า" อย่างเดียว และคุมไม่ให้ซ้ำ
Map
เก็บเป็น "คู่ key-value" และเข้าถึงข้อมูลผ่าน key
4. ความต่างระหว่าง Map กับ Object
Object เหมาะกับโครงสร้างข้อมูลคงที่ของ domain (เช่น user.name, user.email) ส่วน Map เหมาะกับ dictionary/lookup ที่ key เปลี่ยนไปตามข้อมูล
Map มีเมธอดที่ตรงงาน lookup โดยตรง (`set`, `get`, `has`, `delete`) และ iterate ได้เป็นลำดับ insertion ชัดเจน
5. ความต่างระหว่าง Set กับ Array
Array ใช้เก็บข้อมูลแบบลำดับ และอนุญาตค่าซ้ำ ส่วน Set เน้นความไม่ซ้ำ ของข้อมูลโดยธรรมชาติ
ถ้าจุดประสงค์หลักคือ "ลบซ้ำ" หรือ "เช็กว่าเคยมีค่านี้แล้วหรือยัง" Set มักเหมาะกว่า
6. ทำไม Set เหมาะกับการตรวจข้อมูลซ้ำ
เพราะ Set เก็บค่าไม่ซ้ำโดยโครงสร้างอยู่แล้ว การเช็กว่าเคยมีค่าหรือยังด้วย `has` มักทำได้เร็วในค่าเฉลี่ย
กรณีใช้งานยอดนิยมคือ deduplicate array และป้องกันการประมวลผลข้อมูลซ้ำ
7. ทำไม Map เหมาะกับการเข้าถึงข้อมูลแบบ key-value
เมื่อเราต้องการหา value จาก key ซ้ำ ๆ Map จะทำให้อ่านโค้ดง่ายและทำงานได้ไว โดยไม่ต้องไล่ array ทุกครั้ง
ตัวอย่าง: userId -> userProfile, sku -> stock, token -> session
8. ตัวอย่างการใช้ Set
8.1 ลบค่าซ้ำใน array
ใช้ `new Set(array)` แล้วแปลงกลับเป็น array ด้วย spread
8.2 ตรวจว่าค่าเคยมีหรือยัง
ใช้ `has` เช็กก่อนเพิ่มหรือก่อนประมวลผลข้อมูล
9. ตัวอย่างการใช้ Map
9.1 นับจำนวนความถี่ของข้อมูล
ใช้ Map เก็บคู่ค่า -> จำนวนที่พบ
9.2 จับคู่รหัสกับชื่อ
ใช้ key เป็นรหัส เช่น `P-200` และ value เป็นชื่อที่ต้องการแสดง
9.3 เก็บข้อมูลที่ค้นหาบ่อย (cache)
เช็ก key ก่อนเรียก API ถ้ามีแล้วคืนข้อมูลจาก cache ได้เลย
10. ตัวอย่างโค้ด JavaScript สำหรับ Set
ลบค่าซ้ำโดยคงลำดับการเจอครั้งแรก
ใช้ has + add เพื่อกันการทำงานซ้ำ
11. ตัวอย่างโค้ด JavaScript สำหรับ Map
นับจำนวนครั้งที่แต่ละค่าเกิดขึ้น
ทำ lookup จากรหัสได้ทันที
ลดการเรียกซ้ำโดยเก็บผลลัพธ์ไว้ในหน่วยความจำ
12. เมธอดสำคัญที่ควรรู้
เมธอดพื้นฐานที่ใช้บ่อยสุดในงานจริง
เมธอดหลักของการจัดการ key-value
13. ข้อดีของ Set
- จัดการข้อมูลไม่ซ้ำได้ตรงความต้องการ
- เช็กการมีอยู่ของข้อมูลด้วย `has` ได้สะดวก
- โค้ด deduplicate สั้นและอ่านง่าย
14. ข้อดีของ Map
- เหมาะกับงาน key-value lookup อย่างชัดเจน
- รองรับเมธอดครบสำหรับงานอ่าน/เขียน/ตรวจ/ลบ
- ช่วยทำ frequency map, cache, dictionary ได้ดี
15. ข้อควรระวังในการใช้งาน
- Set/Map อิงการเปรียบเทียบแบบ reference สำหรับ object
- ข้อมูลในหน่วยความจำมากเกินไปอาจทำให้ cache บวม
- เลือกโครงสร้างให้ตรงโจทย์: ต้องลำดับ index ใช้ Array, ต้อง key-value ใช้ Map
16. เชื่อมโยงกับแนวคิด Hashing ว่าทำไมจึงเข้าถึงข้อมูลได้เร็ว
โดยแนวคิดภายใน Set และ Map มักอาศัยการจัดการข้อมูลแบบ hashing เพื่อแปลง key หรือ value ให้ไปยังตำแหน่งจัดเก็บที่เข้าถึงได้เร็วในค่าเฉลี่ย
ภาพรวมคือ: รับข้อมูล -> คำนวณ hash -> ไปตำแหน่งที่เกี่ยวข้อง -> ตรวจ/อ่าน/เขียนได้เร็ว โดยยังมีกรณี collision ที่ระบบต้องจัดการภายใน
17. ตัวอย่างโจทย์ที่เหมาะกับ Set
โจทย์ที่ 1: uniqueValues
รับ array ของตัวเลข แล้วคืน array ใหม่ที่ไม่มีค่าซ้ำ โดยคงลำดับการเจอครั้งแรก
แนวเฉลยย่อ: ใช้ Set เก็บข้อมูลและแปลงกลับด้วย spread (`[...new Set(values)]`)
โจทย์ที่ 2: hasDuplicate
คืน true เมื่อพบค่าซ้ำอย่างน้อย 1 ค่า และคืน false เมื่อทุกค่าไม่ซ้ำ
แนวเฉลยย่อ: สร้าง Set ระหว่างวนลูป ถ้า `set.has(value)` ก่อน `add` แปลว่าซ้ำ
18. ตัวอย่างโจทย์ที่เหมาะกับ Map
โจทย์ที่ 3: wordFrequency
รับประโยคแล้วนับจำนวนครั้งของแต่ละคำ (ไม่สนตัวพิมพ์ใหญ่เล็ก)
แนวเฉลยย่อ: แยกคำด้วย `split`, แปลงเป็น lower-case แล้วเก็บผลใน Map
โจทย์ที่ 4: scoreLookup
รับ list นักเรียนและคะแนน จากนั้นตอบคะแนนด้วยรหัสนักเรียนแบบเร็ว
แนวเฉลยย่อ: สร้าง Map จาก `studentId -> score` แล้วใช้ `get` ตอนค้นหา
19. สรุปท้ายบทแบบจำง่าย
จำสั้น ๆ: ถ้าโจทย์คือ "ห้ามซ้ำ" ให้คิดถึง Set, ถ้าโจทย์คือ "จับคู่ key-value" ให้คิดถึง Map
ทั้งสองตัวช่วยให้โค้ด lookup ชัดขึ้น และโดยแนวคิดมักพึ่ง hashing เพื่อประสิทธิภาพที่ดีในงานทั่วไป
20. แบบฝึกหัด 4 ข้อ use playground
ข้อ 1: เขียน `uniqueValues(values)` ด้วย Set
คืน array ใหม่ที่ไม่มีค่าซ้ำ และคงลำดับการเจอครั้งแรก
แนวเฉลยย่อ: `return [...new Set(values)]`
ข้อ 2: เขียน `hasDuplicate(values)` ด้วย Set
คืน true เมื่อพบค่าซ้ำอย่างน้อย 1 ค่า
แนวเฉลยย่อ: วนลูป + `set.has(value)` ก่อน `set.add(value)`
ข้อ 3: เขียน `countFrequency(values)` ด้วย Map
คืน Map ที่เก็บจำนวนครั้งของแต่ละค่า
แนวเฉลยย่อ: `map.set(value, (map.get(value) ?? 0) + 1)`
ข้อ 4: เขียน `createLookupMap(items)` เพื่อค้นหาข้อมูลตาม id
รับรายการวัตถุที่มี `id` แล้วคืน Map เพื่อใช้ lookup ได้เร็ว
แนวเฉลยย่อ: วนลูป `map.set(item.id, item)` และใช้ `map.get(id)` ตอนค้นหา
ภาพประกอบที่ควรมี
ภาพ 1: เปรียบเทียบ Set กับ Array ในเรื่องค่าซ้ำ
ภาพ 2: เปรียบเทียบ Map กับ Object ในเรื่อง key-value
ภาพ 3: Flow ว่า Set ใช้เช็กซ้ำ และ Map ใช้เก็บคู่ข้อมูล