JavaScript數據結構——集合的實現與應用

来源:https://www.cnblogs.com/jaxu/archive/2019/08/02/11287315.html
-Advertisement-
Play Games

與數學中的集合概念類似,集合由一組無序的元素組成,且集合中的每個元素都是唯一存在的。可以回顧一下中學數學中集合的概念,我們這裡所要定義的集合也具有空集(即集合的內容為空)、交集、並集、差集、子集的特性。 在ES6中,原生的Set類已經實現了集合的全部特性,稍後我們會介紹它的用法。 我們使用JavaS ...


  與數學中的集合概念類似,集合由一組無序的元素組成,且集合中的每個元素都是唯一存在的。可以回顧一下中學數學中集合的概念,我們這裡所要定義的集合也具有空集(即集合的內容為空)、交集、並集、差集、子集的特性。

  在ES6中,原生的Set類已經實現了集合的全部特性,稍後我們會介紹它的用法。

  我們使用JavaSctipt的對象來表示集合,下麵是集合類的主要實現方法:

class Set {
    constructor () {
        this.items = {};
    }

    add (value) { // 向集合中添加元素
        if (!this.has(value)) {
            this.items[value] = value;
            return true;
        }
        return false;
    }

    delete (value) { // 從集合中刪除對應的元素
        if (this.has(value)) {
            delete this.items[value];
            return true;
        }
        return false;
    }

    has (value) { // 判斷給定的元素在集合中是否存在
        return this.items.hasOwnProperty(value);
    }

    clear() { // 清空集合內容
        this.items = {};
    }

    size () { // 獲取集合的長度
        return Object.keys(this.items).length;
    }

    values () { // 返回集合中所有元素的內容
        return Object.values(this.items);
    }
}

  在使用JavaScript對象{ }來表示集合時,我們可以像操作數組一樣通過[ ]來設置和獲取集合內元素的值。通過這種方式,在設置集合元素的值時,如果元素不存在,則創建一個新元素,如果元素存在,則修改對應的值;在獲取集合元素的值時,如果元素存在,則返回對應的值,如果元素不存在,則返回undefined。此外,JavaScript對象還提供了一些基礎方法以方便我們對集合進行一些操作,例如hasOwenProperty()方法返回一個表明對象是否具有特定屬性的布爾值,Object.keys()方法返回指定對象的所有屬性名稱的數組,Object.values()方法方法指定對象的所有屬性值的數組。

  上述代碼很簡單,這裡就不再詳細解釋了。下麵是一些測試用例和測試結果:

let set = new Set();
set.add(1);
console.log(set.values()); // [ 1 ]
console.log(set.has(1)); // true
console.log(set.size()); // 1

set.add(2);
console.log(set.values()); // [ 1, 2 ]
console.log(set.has(2)); // true
console.log(set.size()); // 2

set.delete(1);
console.log(set.values()); // [ 2 ]

set.delete(2);
console.log(set.values()); // []

  下麵我們來看看集合的數學運算:並集、交集、差集、子集。

並集

  對於給定的兩個集合,並集返回一個包含兩個集合中所有元素的新集合。示意圖如下:

  並集的實現代碼:

union (otherSet) { // 並集
    let unionSet = new Set();
    this.values().forEach(value => unionSet.add(value));
    otherSet.values().forEach(value => unionSet.add(value));
    return unionSet;
}

  首先遍歷第一個集合,將所有的元素添加到新集合中,然後再遍歷第二個集合,將所有的元素添加到新集合中。然後返回新集合。不用擔心會添加重覆的元素,因為集合的add()方法會自動排除掉已添加的元素。

  測試用例及結果:

let setA = new Set();
setA.add("first");
setA.add("second");
setA.add("third");

let setB = new Set();
setB.add("third");
setB.add("fourth");
setB.add("fifth");
setB.add("sixth");

console.log(setA.union(setB).values()); // [ 'first', 'second', 'third', 'fourth', 'fifth', 'sixth' ]

交集

  對於給定的兩個集合,交集返回一個包含兩個集合中共有元素的新集合。示意圖如下:

  交集的實現代碼:

intersection (otherSet) { // 交集
    let intersectionSet = new Set();
    this.values().forEach(value => {
       if (otherSet.has(value)) intersectionSet.add(value);
    });
    return intersectionSet;
}

  遍歷第一個集合,如果元素出現在第二個集合中,則將它添加到新集合。然後返回新集合。

  測試用例及結果:

let setA = new Set();
setA.add("first");
setA.add("second");
setA.add("third");

let setB = new Set();
setB.add("second");
setB.add("third");
setB.add("fourth");

console.log(setA.intersection(setB).values()); // [ 'second', 'third' ]

差集

  對於給定的兩個集合,差集返回一個包含所有存在於第一個集合且不存在於第二個集合的元素的新集合。示意圖如下:

  差集的實現代碼:

difference (otherSet) { // 差集
    let differenceSet = new Set();
    this.values().forEach(value => {
       if (!otherSet.has(value)) differenceSet.add(value);
    });
    return differenceSet;
}

  遍歷第一個集合,如果元素沒有出現在第二個集合中,則將它添加到新集合。然後返回新集合。

  測試用例及結果:

let setA = new Set();
setA.add("first");
setA.add("second");
setA.add("third");

let setB = new Set();
setB.add("second");
setB.add("third");
setB.add("fourth");

console.log(setA.difference(setB).values()); // [ 'first' ]

子集

  驗證一個給定集合是否是另一個集合的子集,即判斷給定的集合中的所有元素是否都存在於另一個集合中,如果是,則這個集合就是另一個集合的子集,反之則不是。示意圖如下:

  子集的實現代碼:

subset (otherSet) { // 子集
    if (this.size() > otherSet.size()) return false;

    let isSubset = true;
    this.values().every(value => {
        if (!otherSet.has(value)) {
            isSubset = false;
            return false;
        }
        return true;
    });

    return isSubset;
}

  如果集合A比集合B的長度大,則直接返回false,因為這種情況A不可能是B的子集。然後使用every()函數遍歷集合A的所有元素,一旦碰到其中的元素沒有在集合B中出現,則直接返回false,並終止遍歷。這裡我們沒有使用forEach來遍歷集合A,是因為你無法根據某個條件來終止forEach迴圈。考慮下麵這種情況:

var arr = ["first", "second", "third", "fourth"];
arr.forEach(item => {
    if(item === "third") return true;
    console.log(item);
});

  輸出結果是:

first
second
fourth

  很顯然,這裡的return true語句並不能退出forEach迴圈,它只能保證本次迴圈中餘下的語句不被執行,而接下來其它的元素還是會被遍歷到。

  在我們的subset()方法中,如果使用forEach語句,每一次都會遍歷集合中的所有元素,如果遇到其中的元素沒有在集合B中出現,就將isSubset變數的值設置為false,但並不能退出forEach,isSubset變數的值可能會被多次覆蓋。為了提高執行效率,推薦使用every()函數,它會遍歷集合中的元素,直到其中一個返回結果為false,就終止遍歷,並返回false,否則就遍歷所有的元素並返回true。有關every()函數的詳細介紹可以看這裡。與every()函數功能相似還有一個some()函數,它在遍歷集合的過程中,遇到返回結果為true時就終止遍歷,具體內容可以看這裡

  差集的測試用例及結果:

let setA = new Set();
setA.add("first");
setA.add("second");

let setB = new Set();
setB.add("first");
setB.add("second");
setB.add("third");

let setC = new Set();
setC.add("second");
setC.add("third");
setC.add("fourth");

console.log(setA.subset(setB)); // true
console.log(setA.subset(setC)); // false

   文章的開頭說過,ES6提供了原生的Set類,讓我們來看看它的一些使用方法:

let set = new Set();
set.add(1);
set.add(2);
set.add(3);
console.log(set.values()); // [Set Iterator] { 1, 2, 3 }
console.log(set.has(1)); // true
console.log(set.size); // 2

set.delete(1);
console.log(set.values()); // [Set Iterator] { 2, 3 }

set.clear();
console.log(set.values()); // [Set Iterator] {  }

  和前面我們自定義的Set類稍微有一點不同,values()方法返回的不是一個數組,而是Iterator迭代器。另一個就是這裡的size是一個屬性而不是方法,其它部分都和我們前面定義的Set類相同。由於ES6的Set類不包含對集合的數學運算,我們可以按照前面我們提供的方法來對其進行擴充。

  下一章我們將介紹如何用JavaScript來實現字典和散列表。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 現有需求:將oracle資料庫中的數據準實時同步至某ftp伺服器中,以便前端應用能定時從ftp伺服器目錄中取增量數據方法:將加工腳本寫為存儲過程,然後利用shell腳本執行該存儲過程並將增量數據導出為txt文件並傳送到ftp伺服器,利用crontab定時每5分鐘執行一次shell腳本,從而實現ora... ...
  • 前序 縱觀每個優質項目,無論web端還是native原生應用開發,彈窗都是不可忽視的一環,能很大程度上直接決定用戶體驗。如:微信、支付寶、ios都有很成熟的一套彈窗UI展示場景。 最近一直沉迷在react-native開發研究中,學習起來發現沒有想象的難,不過也採坑了不少。鑒於之前有基於h5和小程式 ...
  • 1.指向單個變數的指針; int a,*p; p=&a; 2.數組的指針 (1)一維數組的指針 int a[10],*p; p=a; (2)二維數組的指針 (1)列指針 int a[3][4],*p; p=&a[0][0]; or p=a[0]; or p=*a; (2)行指針 (指向數組的指針) ...
  • jQuery介紹 jQuery是一個輕量級JS庫,使用十分簡單; jQuery的核心是選擇器,用於獲取頁面元素; jQuery提供了大量高效的方法,開發速度大幅提升; jQuery選擇器 jQuery選擇器用於選中需要操作的頁面元素 語法1:jQuery(選擇器表達式) 語法2:$(選擇器表達式) ...
  • 今天在項目中,看到了flat的一個語法,是我之前沒有用過的,所以有必要記錄下來,作為新的知識點,鞏固我自己的知識點; 附贈轉載連接:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Arr ...
  • 目錄 為什麼要討論this this是什麼 如何改變this的指向 為什麼要討論this this是什麼 如何改變this的指向 為什麼要討論this 代碼一: 會列印出什麼呢?是 ' I am aa ' 嗎, 結果是: 原因: 此時 this 指向 window 對象, this.aa 等同於 w ...
  • 居中是我們使用css來佈局時常遇到的情況。使用css來進行居中時,有時一個屬性就能搞定,有時則需要一定的技巧才能相容到所有瀏覽器,本文就居中的一些常用方法做個簡單的介紹。 註:本文所講方法除了特別說明外,都是相容IE6+、谷歌、火狐等主流瀏覽器的。 先來說幾種簡單的、人畜無害的居中方法: 1. 把m ...
  • 前置閱讀:簡述JavaScript模塊化(一) 在前面一文中,我們對前端模塊化所經歷的三個階段進行了瞭解: CommonJs,由於是同步的,所以主要應用於伺服器端,以Node.js為代表。 AMD,非同步模塊定義,預載入,推薦依賴前置。以require.js為代表。 CMD,通用模塊載入,懶載入,推薦 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...