Set (Tập hợp) là cấu trúc dữ liệu lưu trữ các giá trị duy nhất (unique), không có key-value, chỉ có value. ES6 cung cấp Set chuẩn, nhưng có thể tự triển khai để hiểu bản chất.
1. Triển khai Custom MySet (ES6 Class) - Học tập
class MySet {
constructor() {
this.container = {}; // Dùng Object làm backend (key = value)
}
// Hiển thị
display() {
console.log(this.container);
}
// Kiểm tra tồn tại
has(val) {
return this.container.hasOwnProperty(val);
}
// Thêm
add(val) {
if (!this.has(val)) {
this.container[val] = val; // Key = Value
return true; // Đã thêm mới
}
return false; // Đã tồn tại
}
// Xóa
delete(val) {
if (this.has(val)) {
delete this.container[val];
return true;
}
return false;
}
// Xóa tất cả
clear() {
this.container = {};
}
// Duyệt
forEach(callback) {
for (let prop in this.container) {
// prop là key (string), value = this.container[prop]
// Vì key=value, nên callback(prop) hoặc callback(this.container[prop])
callback(prop); // Truyền value (đã là string key)
}
}
// Union (Hợp) - Static method
static union(s1, s2) {
if (!(s1 instanceof MySet) || !(s2 instanceof MySet)) {
console.log("Not MySet instances");
return null;
}
const newSet = new MySet();
s1.forEach(elem => newSet.add(elem));
s2.forEach(elem => newSet.add(elem));
return newSet;
}
// Difference (Hiệu) - Static method: s1 - s2
static difference(s1, s2) {
if (!(s1 instanceof MySet) || !(s2 instanceof MySet)) {
console.log("Not MySet instances");
return null;
}
const newSet = new MySet();
s1.forEach(elem => newSet.add(elem));
s2.forEach(elem => newSet.delete(elem));
return newSet;
}
// Intersection (Giao) - Bonus
static intersection(s1, s2) {
if (!(s1 instanceof MySet) || !(s2 instanceof MySet)) return null;
const newSet = new MySet();
s1.forEach(elem => { if (s2.has(elem)) newSet.add(elem); });
return newSet;
}
}
// Test MySet
const setA = new MySet();
setA.add(1); setA.add(2); setA.add(2); // Thêm trùng -> bỏ qua
setA.add(3);
setA.display(); // { '1': 1, '2': 2, '3': 3 }
console.log(setA.has(2)); // true
setA.delete(2);
setA.display(); // { '1': 1, '3': 3 }
2. ES6 Set (Chuẩn, Khuyên dùng Production)
// Tạo
const set1 = new Set();
const set2 = new Set([1, 2, 3, 3, 4]); // Tự động unique -> {1, 2, 3, 4}
// Thêm
set1.add(10).add(20).add(30); // Chainable
// Kiểm tra
console.log(set1.has(10)); // true
console.log(set1.has(99)); // false
// Xóa
set1.delete(20); // true
set1.delete(99); // false
// Kích thước
console.log(set1.size); // 2
// Duyệt
set1.forEach(val => console.log(val)); // 10, 30
for (const val of set1) console.log(val); // 10, 30
// Chuyển Array
const arr = [...set1]; // [10, 30]
const arr2 = Array.from(set1);
// Xóa tất cả
set1.clear();
3. Các phép toán Set (Union, Difference, Intersection) - ES6
ES6 Set KHÔNG có sẵn union/difference/intersection. Tự viết helper hoặc extends.
Union (Hợp): A ∪ B
function union(setA, setB) {
if (!(setA instanceof Set) || !(setB instanceof Set)) return null;
return new Set([...setA, ...setB]);
}
// Hoặc extends
Set.union = function(s1, s2) {
if (!(s1 instanceof Set) || !(s2 instanceof Set)) return null;
return new Set([...s1, ...s2]);
};
// Test
const a = new Set([1, 2, 3, 4]);
const b = new Set([3, 4, 5, 6]);
console.log(Set.union(a, b)); // Set {1, 2, 3, 4, 5, 6}
Difference (Hiệu): A - B
function difference(setA, setB) {
if (!(setA instanceof Set) || !(setB instanceof Set)) return null;
const result = new Set(setA);
for (const val of setB) result.delete(val);
return result;
}
// Hoặc extends
Set.difference = function(s1, s2) {
if (!(s1 instanceof Set) || !(s2 instanceof Set)) return null;
const result = new Set(s1);
for (const val of s2) result.delete(val);
return result;
};
// Test
console.log(Set.difference(a, b)); // Set {1, 2}
Intersection (Giao): A ∩ B
function intersection(setA, setB) {
if (!(setA instanceof Set) || !(setB instanceof Set)) return null;
return new Set([...setA].filter(x => setB.has(x)));
}
// Test
console.log(Set.intersection(a, b)); // Set {3, 4}
So sánh MySet (Custom) vs ES6 Set
| Đặc điểm | MySet (Object backend) | ES6 Set |
|---|---|---|
| Value Type | Chỉ String/Symbol (Object key) | Bất kỳ (Object, Function, NaN, ...) |
| NaN handling | NaN key = "NaN" string | Hỗ trợ NaN đúng chuẩn (NaN === NaN trong Set) |
| Size | Object.keys().length | .size property |
| Iteration Order | Insertion order (ES2015+ Object) | Insertion order (Chuẩn) |
| Perf Add/Delete | Tốt | Tối ưu hơn |
| Methods | Custom (union, diff static) | Core: add, delete, has, clear, forEach, size |
Ứng dụng Set thực tế
- Loại bỏ trùng lặp Array:
[...new Set(arr)]. - Kiểm tra tồn tại O(1):
allowedValues.has(input). - Phép toán tập hợp: Tag system, Permission (Union/Intersection/Difference).
- Unique ID tracking: Visited nodes in Graph/DFS/BFS.
Tóm lại: Set lưu giá trị unique. ES6 Set là chuẩn, mạnh, hỗ trợ mọi kiểu, NaN đúng. Custom MySet dùng Object backend (chỉ string key). ES6 Set thiếu union/diff/intersection -> tự viết helper hoặc extends prototype. Ứng dụng: unique array, O(1) lookup, set operations.