[Medium] Set & Map
1. What are Set and Map?
什麼是 Set 和 Map?
Set 和 Map 是 ES6 引入的兩種新的資料結構,它們提供了比傳統物件和陣列更適合特定場景的解決方案。
Set(集合)
定義:Set 是一種值唯一的集合,類似於數學中的集合概念。
特點:
- 儲存的值不會重複
- 使用
===來判斷值是否相等 - 保持插入順序
- 可以儲存任何類型的值(原始型別或物件)
基本用法:
// 建立 Set
const set = new Set();
// 新增值
set.add(1);
set.add(2);
set.add(2); // 重複值不會被加入
set.add('hello');
set.add({ name: 'John' });
console.log(set.size); // 4
console.log(set); // Set(4) { 1, 2, 'hello', { name: 'John' } }
// 檢查值是否存在
console.log(set.has(1)); // true
console.log(set.has(3)); // false
// 刪除值
set.delete(2);
console.log(set.has(2)); // false
// 清空 Set
set.clear();
console.log(set.size); // 0
從陣列建立 Set:
// 去除陣列中的重複值
const arr = [1, 2, 2, 3, 3, 3];
const uniqueSet = new Set(arr);
console.log(uniqueSet); // Set(3) { 1, 2, 3 }
// 轉回陣列
const uniqueArr = [...uniqueSet];
console.log(uniqueArr); // [1, 2, 3]
// 簡寫
const uniqueArr2 = [...new Set(arr)];
Map(映射)
定義:Map 是一種鍵值對的集合,類似於物件,但鍵可以是任何類型。
特點:
- 鍵可以是任何類型(字串、數字、物件、函式等)
- 保持插入順序
- 有
size屬性 - 迭代順序與插入順序一致
基本用法:
// 建立 Map
const map = new Map();
// 新增鍵值對
map.set('name', 'John');
map.set(1, 'one');
map.set(true, 'boolean');
map.set({ id: 1 }, 'object key');
// 取得值
console.log(map.get('name')); // 'John'
console.log(map.get(1)); // 'one'
// 檢查鍵是否存在
console.log(map.has('name')); // true
// 刪除鍵值對
map.delete('name');
// 取得大小
console.log(map.size); // 3
// 清空 Map
map.clear();
從陣列建立 Map:
// 從二維陣列建立
const entries = [
['name', 'John'],
['age', 30],
['city', 'Taipei'],
];
const map = new Map(entries);
console.log(map.get('name')); // 'John'
// 從物件建立
const obj = { name: 'John', age: 30 };
const map2 = new Map(Object.entries(obj));
console.log(map2.get('name')); // 'John'
2. Set vs Array
Set 與陣列的差異
| 特性 | Set | Array |
|---|---|---|
| 重複值 | 不允許 | 允許 |
| 索引存取 | 不支援 | 支援 |
| 查找效能 | O(1) | O(n) |
| 插入順序 | 保持 | 保持 |
| 常用方法 | add, has, delete | push, pop, indexOf |
使用場景:
// ✅ 適合使用 Set:需要唯一值
const userIds = new Set([1, 2, 3, 2, 1]);
console.log([...userIds]); // [1, 2, 3]
// ✅ 適合使用 Set:快速檢查存在性
const visitedPages = new Set();
visitedPages.add('/home');
visitedPages.add('/about');
if (visitedPages.has('/home')) {
console.log('已訪問過首頁');
}
// ✅ 適合使用 Array:需要索引或重複值
const scores = [100, 95, 100, 90]; // 允許重複
console.log(scores[0]); // 100
3. Map vs Object
Map 與物件的差異
| 特性 | Map | Object |
|---|---|---|
| 鍵的類型 | 任何類型 | 字串或 Symbol |
| 大小 | size 屬性 | 需手動計算 |
| 預設鍵 | 無 | 有原型鏈 |
| 迭代順序 | 插入順序 | ES2015+ 保持插入順序 |
| 效能 | 頻繁增刪較快 | 一般情況較快 |
| JSON | 不直接支援 | 原生支援 |
使用場景:
// ✅ 適合使用 Map:鍵不是字串
const userMetadata = new Map();
const user1 = { id: 1 };
const user2 = { id: 2 };
userMetadata.set(user1, { lastLogin: '2024-01-01' });
userMetadata.set(user2, { lastLogin: '2024-01-02' });
console.log(userMetadata.get(user1)); // { lastLogin: '2024-01-01' }
// ✅ 適合使用 Map:需要頻繁增刪
const cache = new Map();
cache.set('key1', 'value1');
cache.delete('key1');
cache.set('key2', 'value2');
// ✅ 適合使用 Object:靜態結構、需要 JSON
const config = {
apiUrl: 'https://api.example.com',
timeout: 5000,
};
const json = JSON.stringify(config); // 可直接序列化
4. Common Interview Questions
常見面試題目
題目 1:去除陣列重複值
請實作一個函式,去除陣列中的重複值。
function removeDuplicates(arr) {
// 你的實作
}
點擊查看答案
方法 1:使用 Set(推薦)
function removeDuplicates(arr) {
return [...new Set(arr)];
}
console.log(removeDuplicates([1, 2, 2, 3, 3, 3])); // [1, 2, 3]
console.log(removeDuplicates(['a', 'b', 'a', 'c'])); // ['a', 'b', 'c']
方法 2:使用 filter + indexOf
function removeDuplicates(arr) {
return arr.filter((value, index) => arr.indexOf(value) === index);
}
方法 3:使用 reduce
function removeDuplicates(arr) {
return arr.reduce((acc, value) => {
if (!acc.includes(value)) {
acc.push(value);
}
return acc;
}, []);
}
效能比較:
- Set 方法:O(n),最快
- filter + indexOf:O(n²),較慢
- reduce + includes:O(n²),較慢
題目 2:檢查陣列是否有重複值
請實作一個函式,檢查陣列中是否有重複值。
function hasDuplicates(arr) {
// 你的實作
}
點擊查看答案
方法 1:使用 Set(推薦)
function hasDuplicates(arr) {
return new Set(arr).size !== arr.length;
}
console.log(hasDuplicates([1, 2, 3])); // false
console.log(hasDuplicates([1, 2, 2, 3])); // true
方法 2:使用 Set 的 has 方法
function hasDuplicates(arr) {
const seen = new Set();
for (const value of arr) {
if (seen.has(value)) {
return true;
}
seen.add(value);
}
return false;
}
方法 3:使用 indexOf
function hasDuplicates(arr) {
return arr.some((value, index) => arr.indexOf(value) !== index);
}
效能比較:
- Set 方法 1:O(n),最快
- Set 方法 2:O(n),平均情況下可能提前結束
- indexOf 方法:O(n²),較慢