Skip to main content

ES6 Set vs. Map

Set 和 Map 是 ES6 引入的兩種資料結構,它們用來處理資料集合,但用途和特性不同。以下是它們的詳細比較:

1. Set

  • 定義:Set 是一個儲存唯一值的集合,任何型別的值(原始值或物件)都可以儲存,但每個值只會出現一次。

  • 特點

    • 去重複:自動移除重複的值。

    • 無鍵值對:只有值,沒有鍵。

    • 迭代順序:值的插入順序會被保留,迭代時按插入順序返回。

    • 用途:適合用來儲存不重複的資料,例如去重陣列、檢查值是否存在。

    • 大小:透過 size 屬性取得元素數量。

    • 常用方法

      • add(value):新增值。

      • has(value):檢查值是否存在。

      • delete(value):刪除值。

      • clear():清空所有值。

      • forEach(callback):迭代每個值。

      • 可使用 for...of 或展開運算子 (...) 迭代。

2. Map

  • 定義:Map 是一個儲存鍵值對的集合,鍵和值可以是任何型別(原始值或物件)。

  • 特點

    • 鍵值對:每個元素由鍵和值組成,鍵是唯一的。

    • 靈活的鍵:鍵可以是物件、函式等,而不僅限於字串或符號(不像普通物件)。

    • 迭代順序:鍵值對的插入順序會被保留。

    • 用途:適合用來儲存有鍵值對應關係的資料,例如字典、物件的增強版。

    • 大小:透過 size 屬性取得鍵值對數量。

    • 常用方法

      • set(key, value):新增或更新鍵值對。

      • get(key):取得指定鍵的值。

      • has(key):檢查鍵是否存在。

      • delete(key):刪除指定鍵值對。

      • clear():清空所有鍵值對。

      • forEach(callback):迭代每個鍵值對。

      • 可使用 for...of 迭代鍵值對、鍵或值。

主要差異

特性SetMap
資料結構僅儲存值(無鍵)儲存鍵值對
唯一性值必須唯一鍵必須唯一,值可重複
鍵的型別無鍵鍵可以是任何型別(包括物件)
用途去重複、檢查值是否存在鍵值對應、儲存結構化資料
查詢方法has(value)has(key)、get(key)
大小sizesize

在 React 中的使用範例

以下是一個完整的 React 專案範例,展示如何在 React 組件中使用 Set 和 Map,並以簡單的 UI 呈現它們的功能。這個範例會建立一個應用程式,讓使用者輸入資料,展示 Set 的去重功能和 Map 的鍵值對管理。

範例需求

  • 使用 Set 來儲存不重複的使用者輸入名稱。

  • 使用 Map 來儲存名稱和對應的輸入次數(鍵值對)。

  • 提供輸入框和按鈕,讓使用者新增資料,並顯示結果。

完整程式碼

import React, { useState } from "react";

function App() {
// 狀態管理
const [inputName, setInputName] = useState(""); // 輸入框的值
const [nameSet, setNameSet] = useState(new Set()); // 使用 Set 儲存不重複名稱
const [nameMap, setNameMap] = useState(new Map()); // 使用 Map 儲存名稱和次數

// 處理輸入框變更
const handleInputChange = (e) => {
setInputName(e.target.value);
};

// 處理新增按鈕
const handleAddName = () => {
if (inputName.trim() === "") {
alert("請輸入名稱!");
return;
}

// 更新 Set
const newSet = new Set(nameSet); // 複製現有 Set
newSet.add(inputName); // 新增名稱到 Set(自動去重)
setNameSet(newSet);

// 更新 Map
const newMap = new Map(nameMap); // 複製現有 Map
const currentCount = newMap.get(inputName) || 0; // 取得當前次數,預設為 0
newMap.set(inputName, currentCount + 1); // 更新次數
setNameMap(newMap);

// 清空輸入框
setInputName("");
};

// 渲染 Set 的內容
const renderSetContent = () => {
return Array.from(nameSet).map((name, index) => (
<li key={index}>{name}</li>
));
};

// 渲染 Map 的內容
const renderMapContent = () => {
return Array.from(nameMap).map(([name, count], index) => (
<li key={index}>
{name}: {count}
</li>
));
};

return (
<div style={{ padding: "20px" }}>
<h1>SetMap 範例</h1>

{/* 輸入框和按鈕 */}
<div>
<input
type="text"
value={inputName}
onChange={handleInputChange}
placeholder="輸入名稱"
/>
<button onClick={handleAddName}>新增</button>
</div>

{/* 顯示 Set 結果 */}
<div>
<h2>不重複名稱 (Set)</h2>
<p>總數量: {nameSet.size}</p>
<ul>{renderSetContent()}</ul>
</div>

{/* 顯示 Map 結果 */}
<div>
<h2>名稱與次數 (Map)</h2>
<p>總數量: {nameMap.size}</p>
<ul>{renderMapContent()}</ul>
</div>
</div>
);
}

export default App;

程式碼說明

  1. 狀態管理

    • 使用 useState 管理輸入框的值 (inputName)、儲存名稱的 Set (nameSet) 和儲存名稱與次數的 Map (nameMap)。

    • 因為 Set 和 Map 是物件,直接修改不會觸發 React 重新渲染,所以我們使用複製的方式更新它們。

  2. 處理輸入

    • handleInputChange:更新輸入框的值。

    • handleAddName:

      • 檢查輸入是否為空。

      • 更新 Set:使用 add 新增名稱,自動去重。

      • 更新 Map:使用 set 更新名稱的計數,若名稱不存在則初始化為 0。

      • 清空輸入框。

  3. 渲染結果

    • renderSetContent:將 Set 轉為陣列並渲染為清單,顯示不重複的名稱。

    • renderMapContent:將 Map 轉為陣列,顯示名稱和對應的輸入次數。

    • 使用 size 屬性顯示 Set 和 Map 的元素數量。

  4. UI 設計

    • 包含一個輸入框和按鈕,讓使用者輸入名稱。

    • 顯示兩個區塊:一個展示 Set 的不重複名稱,另一個展示 Map 的名稱和次數。

使用場景建議

  • 使用 Set

    • 當你需要儲存不重複的值,例如:

      • 過濾重複的標籤(tags)。

      • 儲存唯一的使用者 ID。

      • 檢查某個值是否已經存在。

    • 範例:移除陣列中的重複元素:

      const array = [1, 2, 2, 3, 3, 4];
      const uniqueArray = [...new Set(array)]; // [1, 2, 3, 4]
  • 使用 Map

    • 當你需要儲存鍵值對,且鍵可能是複雜型別(例如物件),例如:

      • 儲存使用者的設定(鍵是使用者物件,值是設定)。

      • 記錄每個項目的計數或屬性。

    • 範例:以物件作為鍵:

      const map = new Map();
      const keyObj = { id: 1 };
      map.set(keyObj, "使用者資料");
      console.log(map.get(keyObj)); // '使用者資料'

常見問題

  1. 為什麼不用陣列或物件代替 Set 和 Map?

    • 陣列:不自動去重,檢查值是否存在需要遍歷,效率較低(O(n))。

    • 物件:鍵只能是字串或符號,無法直接使用物件作為鍵,且沒有內建的 size 屬性。

    • Set 和 Map 提供更高的效率(大多數操作為 O(1))和更靈活的鍵型別。

  2. 在 React 中更新 Set 和 Map 時為什麼要複製?

    • React 的狀態更新需要不可變性(immutability)。直接修改 Set 或 Map 不會觸發重新渲染,因此需要創建新實例。
  3. Set 和 Map 的效能如何?

    • 兩者內部使用哈希表,查詢和插入操作通常為 O(1)。

    • 比陣列的 includes(O(n))或物件的鍵檢查更高效。


總結

  • Set:適合處理不重複的值,簡單高效,常用於去重或快速檢查。

  • Map:適合儲存鍵值對,鍵型別靈活,適用於結構化資料。

  • 在 React 中,使用 Set 和 Map 時,記得複製實例以確保狀態更新正確。