Phép hợp của hai tập hợp (set union) trả về một tập mới chứa tất cả các phần tử duy nhất từ cả hai tập gốc. Giống như hiệu, JavaScript Set chuẩn không có sẵn phương thức này, nhưng việc triển khai rất trực quan.
Triển khai với class Set tùy chỉnh (MySet)
class MySet {
constructor() {
this.items = {};
}
add(value) {
if (!this.has(value)) {
this.items[value] = value;
return true;
}
return false;
}
has(value) {
return Object.prototype.hasOwnProperty.call(this.items, value);
}
forEach(callback) {
for (const key in this.items) {
if (this.has(key)) callback(key);
}
}
// Phương thức tĩnh union
static union(s1, s2) {
if (!(s1 instanceof MySet) || !(s2 instanceof MySet)) {
console.log("Đối tượng không phải kiểu MySet");
return null;
}
const newSet = new MySet();
s1.forEach(elem => newSet.add(elem));
s2.forEach(elem => newSet.add(elem)); // add() tự loại trùng
return newSet;
}
display() {
console.log(this.items);
}
}
// Test
const testSet1 = new MySet();
testSet1.add(1);
testSet1.add(2);
const testSet2 = new MySet();
testSet2.add(2);
testSet2.add(5);
const testSet3 = MySet.union(testSet1, testSet2);
testSet3.display(); // { '1': '1', '2': '2', '5': '5' }
Mở rộng cho Set chuẩn ES6
Set.union = function(s1, s2) {
if (!(s1 instanceof Set) || !(s2 instanceof Set)) {
console.log("Đối tượng không phải kiểu Set");
return null;
}
const newSet = new Set();
s1.forEach(elem => newSet.add(elem));
s2.forEach(elem => newSet.add(elem));
return newSet;
};
// Test
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([2, 3]);
console.log(Set.union(setA, setB)); // Set { 1, 2, 3, 4 }
Cách viết hiện đại, ngắn gọn (Khuyên dùng)
Tận dụng spread operator và constructor Set tự động loại bỏ trùng lặp:
// Hàm thuần túy
const union = (setA, setB) => new Set([...setA, ...setB]);
// Hoặc mở rộng prototype
Set.prototype.union = function(otherSet) {
return new Set([...this, ...otherSet]);
};
// Usage
const a = new Set([1, 2, 3, 4]);
const b = new Set([2, 3, 5]);
console.log(union(a, b)); // Set { 1, 2, 3, 4, 5 }
console.log(a.union(b)); // Set { 1, 2, 3, 4, 5 }
So sánh các cách tiếp cận
| Cách làm | Ưu điểm | Nhược điểm |
|---|---|---|
| forEach + add | Dễ hiểu, tương thích cũ | Code dài, chậm hơn spread |
| Spread operator [...a, ...b] | Ngắn gọn, nhanh, ES6+ | Cần hỗ trợ iterable |
| Prototype method | Cú pháp OOP tự nhiên | Ghi đè prototype built-in (cân nhắc) |
Lưu ý
- Phép hợp không thay đổi hai tập gốc (immutable approach).
- Độ phức tạp: O(n + m) — tối ưu nhờ
Setnội bộ dùng hash table. - Có thể mở rộng cho N tập:
new Set([...set1, ...set2, ...set3]).