天天看點

【JS資料結構與算法】數組

寫在前面

幾乎所有所有的程式設計語言中都支援了數組,JavaScript也不例外。在很多的程式設計語言中數組是用來存放一系列同種類型的值的,但是在我們的JS中,它卻可以存放不同類型的值,而且它的長度還可以随着我們添加的值動态增加,是以在JS裡面使用數組,會讓我們有一種如絲般順滑的感覺。

接下來的内容我們按如下圖所示展開給大家介紹。

【JS資料結構與算法】數組

建立和初始化數組

在JS中建立和初始化數組有如下幾種方式:

           //數組初始化、指派方式
            let dataArray_01 = new Array(); //初始化一個空數組
            let dataArray_02 = new Array(5); //初始化一個長度為5的數組,如果裡面有大于等于2個以上元素,就相當于給數組指派
            let dataArray_03 = new Array('X北辰北', 'xbeichen.cn', 'Geov', 23); //建立一個含有四個元素的數組并指派
            let dataArray_04 = []; //同dataArray_01
            let dataArray_05 = ['X北辰北', 'xbeichen.cn', 'Geov', 23]; //同dataArray_03           

前三種方式我們使用JS内置的Array數組對象來執行個體化數組,後兩種方式直接通過簡寫方式來執行個體化數組,這兩種方式執行個體化出來的數組在用法上并沒有差别,實際開發中我們推薦使用後兩種中括号的方式去建立和初始化數組。

如果我們想擷取數組中的元素個數,或者說想擷取數組長度的話,可以直接使用length屬性去擷取,如下:

console.log(dataArray_01.length);           

通路數組元素和疊代數組

通路數組中特定元素直接通過中括号加數組下标的方式通路,下标從0開始計數。

數組疊代可以通過一層for循環來實作,如下:

           //通路數組元素、疊代數組
            console.log(dataArray_05[1]); //輸出'xbeichen.cn'
            for (let i = 0; i < dataArray_05.length; i++) {
                //疊代數組中所有元素,并輸出
                console.log(dataArray_05[i]);
            }           

在數組中添加元素和删除元素

在數組中添加和删除元素分為以下三種情況;

  • 在數組頭部添加元素、删除元素
  • 在數組尾部添加元素、删除元素
  • 在數組中間某一位置添加元素、删除元素

下面我們就以上三種情況,分别來介紹下該如何去操作。

1、在數組頭部添加元素、删除元素

在數組的頭部位置添加元素的話,我們需要先将數組中每一項位置向後移動一位,騰出下标是0的位置,然後将要添加的元素添加到這個位置即可,代碼如下:

           //頭部添加元素
            let originData = [1, 2, 3, 4, 5];
            function preInsert(arr, value) {
                //周遊數組中每一項
                for (let i = arr.length; i >= 0; i--) {
                    //将每一項元素位置後移一位,騰出arr[0]的位置
                    arr[i] = arr[i - 1];
                }
                arr[0] = value; //arr[0]位置插入新值
                return arr;
            }
            console.log(preInsert(originData, 88)); //輸出[88, 1, 2, 3, 4, 5]           

除了上述直接上手自己實作之外,JS中的數組提供了一個方法,我們直接可以通過這方法來實作數組頭部位置的元素添加,如下:

           originData.unshift(99);
            console.log(originData); //輸出[99, 88, 1, 2, 3, 4, 5]           

在數組頭部位置删除元素的話,同理,我們隻需要将數組中每一個元素往前移動一位即可,這樣一來,數組的第二項就覆寫了原有的第一項元素,完成了數組頭部位置元素的删除。但是這樣做完的話,我們數組的長度是沒有改變的,因為最後一項是undefined,是以我們新定義一個數組,将删除元素後的數組裡面不是undefined的元素指派到新數組,然後将新數組傳回即可,如下:

           //頭部删除元素
            let originData = [1, 2, 3, 4, 5];
            function preRemove(arr) {
                let newArray = []; //定義一個新數組,用于存放删除後數組中不是undefined的元素
                //周遊原數組,将每一項向前移動一位,覆寫前一位元素
                for (let i = 0; i < arr.length; i++) {
                    arr[i] = arr[i + 1];
                }
                //周遊完成覆寫後的數組,去除掉覆寫後的數組中最後一項值為undefined的元素
                for (let j = 0; j < arr.length; j++) {
                    if (arr[j] != undefined) {
                        newArray.push(arr[j]); //push方法用于向數組中尾部添加元素
                    }
                }
                return newArray;
            }
            console.log(preRemove(originData)); //輸出[2, 3, 4, 5]           

同樣的,删除數組中第一個元素,JS中的數組提供了一個方法,我們直接可以通過這方法來實作數組頭部位置的元素删除,如下:

           originData.shift();
            console.log(originData); //輸出[3, 4, 5]           

2、在數組尾部添加元素、删除元素

在數組的尾部添加元素相比于在頭部位置添加元素的話顯得特别簡單,我們隻需要在數組的最後位置增加一個空位,然後将值賦上去即可,這樣操作可行是因為在JS中,數組是可以動态增長的,如下:

           //尾部增加元素
            let originData = [1, 2, 3, 4, 5];
            function laterInsert(arr, value) {
                //直接在數組最後位置添加空位并指派即可,
                //因為數組實際長度是arr.length-1,arr[arr.length]就相當于在數組最後位置增加了一個空位
                arr[arr.length] = value;
                return arr;
            }
            console.log(laterInsert(originData, 88)); //輸出[1, 2, 3, 4, 5, 88]           

除了上述直接上手自己實作之外,JS中的數組提供了一個方法,我們直接可以通過這方法來實作數組尾部位置的元素添加,如下:

           originData.push(99);
            console.log(originData); //輸出[1, 2, 3, 4, 5, 88, 99]           

在數組最後位置删除元素,我們也不需要移動元素位置,隻需要将原數組中的n-1(n是原數組長度)個元素指派到一個新數組,然後傳回這個新數組即可,如下:

           //尾部删除元素
            let originData = [1, 2, 3, 4, 5];
            function laterRemove(arr) {
                let newArray = []; //定義一個新數組
                for (let i = 0; i < arr.length - 1; i++) {
                    //循環周遊原數組的前n-1項,并将其每一項都指派到新數組
                    newArray[i] = arr[i];
                }
                return newArray;
            }
            console.log(laterRemove(originData)); //輸出[1, 2, 3, 4]           

同樣的,删除數組中最後一個元素,JS中的數組提供了一個方法,我們直接可以通過這方法來實作數組尾部位置的元素删除,如下:

           originData.pop();
            console.log(originData); //輸出[1, 2, 3]           

3、在數組中間某一位置添加元素、删除元素

在數組中間的某一位置要實作添加元素和删除元素的話其實我們自己寫代碼也是可以實作的,隻需要将上述代碼進行修改、增加判斷條件這些就可以做到,在這裡我們就不做詳細的介紹。我們如果想在數組中間某一位置添加元素和删除元素的話,在這裡給大家介紹splice()這個方法,這個方法既可以實作任意位置添加元素,也可以實作任意位置元素的删除,用法如下:

           //在中間某一位置删除元素
            let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9];
            //從索引是2的位置開始,删除4個元素,即删除originData[2]、originData[3]、originData[4]、originData[5]
            originData.splice(2, 4);
            console.log(originData); //輸出[1, 2, 7, 8, 9]           
           //在中間某一位置添加元素
            let originData = [1, 2, 3, 4];
            //從索引是2的位置開始,删除0個元素,然後在此位置添加從第三個參數開始依次往後的各個元素
            //即在索引是2的位置處依次插入77、88、99這三個元素
            originData.splice(2, 0, 77, 88, 99);
            console.log(originData); //輸出[1, 2, 77, 88, 99, 3, 4]           

二維數組和多元數組

在JS中是不支援二維數組(矩陣)、多元數組這些的,它僅僅支援一維數組。但是我們可以通過數組套數組的方式來實作二維數組或者任一多元數組,代碼如下:

           //定義二維數組、疊代二維數組
            let arrayData2D = []; //定義二維數組
            arrayData2D[0] = [1, 2, 3, 4, 5];
            arrayData2D[1] = [6, 7, 8, 9, 10];
            console.table(arrayData2D);
​
            //疊代
            for (let i = 0; i < arrayData2D.length; i++) {
                for (let j = 0; j < arrayData2D[i].length; j++) {
                    console.log(arrayData2D[i][j]);
                }
            }           
【JS資料結構與算法】數組

多元數組的話跟上述一樣,不過數組套數組部分我們直接通過for循環來做,如下:

           //定義三維數組、疊代三維數組
            let arrayData3D = [];
            for (let i = 0; i < 5; i++) {
                arrayData3D[i] = []; //初始化每一個緯度的數組
                for (let j = 0; j < 5; j++) {
                    arrayData3D[i][j] = []; //初始化每一個緯度的數組
                    for (let k = 0; k < 5; k++) {
                        arrayData3D[i][j][k] = i + j + k; //數組中的每一項存儲目前坐标的數值之和
                    }
                }
            }
            console.table(arrayData3D);
​
            //疊代
            for (let i = 0; i < arrayData3D.length; i++) {
                for (let j = 0; j < arrayData3D[i].length; j++) {
                    for (let k = 0; k < arrayData3D[i][j].length; k++) {
                        console.log(arrayData3D[i][j][k]);
                    }
                }
            }           
【JS資料結構與算法】數組

以上我們展示了一下三維數組的執行個體化和周遊,其他四維數組、五維數組……這些高維數組,我們隻需要依次增加for循環去做就可以了,不過實際開發中三維和四維數組已經用的不太多了,是以大家沒必要再去學習更高維的數組了。

JS數組方法

JS中的數組為我們提供了很多的方法,供我們去操作數組,能熟練使用這些方法的話會對我們接下來實作其他資料結構帶來便利,我們來看看以下幾種核心方法:

下表詳述了數組的一些核心方法,其中的一些我們已經學習過了。

方 法 描 述
concat 連接配接 2 個或更多數組,并傳回結果
every 對數組中的每個元素運作給定函數,如果該函數對每個元素都傳回 true ,則傳回 true
filter 對數組中的每個元素運作給定函數,傳回該函數會傳回 true 的元素組成的數組
forEach 對數組中的每個元素運作給定函數。這個方法沒有傳回值
join 将所有的數組元素連接配接成一個字元串
indexOf 傳回第一個與給定參數相等的數組元素的索引,沒有找到則傳回 -1
lastIndexOf 傳回在數組中搜尋到的與給定參數相等的元素的索引裡最大的值
map 對數組中的每個元素運作給定函數,傳回每次函數調用的結果組成的數組
reverse 颠倒數組中元素的順序,原先第一個元素現在變成最後一個,同樣原先的最後一個元素變成了現在的第一個
slice 傳入索引值,将數組裡對應索引範圍内的元素作為新數組傳回
some 對數組中的每個元素運作給定函數,如果任一進制素傳回 true ,則傳回 true
sort 按照字母順序對數組排序,支援傳入指定排序方法的函數作為參數
toString 将數組作為字元串傳回
valueOf 和 toString 類似,将數組作為字元串傳回

除了上述提出的方法之外,我們在文章開始的時候已經介紹過push()、pop()、shift()、unshift()、splice()這些方法,接下來我們再挑幾個上述清單中的方法給大家介紹一下。

1、數組合并

數組的合并如果我們想自己編碼實作的話很簡單,隻需要疊代各個數組中的元素,然後将其最終指派到我們的結果數組中就可以,但是JS的數組對象給我們提供了一個用于數組合并的方法concat(),用法如下:

           //數組合并
            let arrayData_01 = [1, 2, 3];
            let arrayData_02 = [8, 9];
            let resultData = arrayData_01.concat(88, 'testValue', arrayData_02);
            console.log(resultData); //輸出[1, 2, 3, 88, "testValue", 8, 9]           

2、數組疊代——every

every()方法主要是用來檢測數組中的所有元素是否滿足某一條件,如果有一個元素不滿足條件就直接傳回false,剩餘元素不再進行檢測。

every()方法不會改變原數組。

使用方法如下:

           let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            let resultData = originData.every(function (value) {
                return value % 2 === 0 ? true : false;
            });
            console.log(resultData); //輸出false,因為第一項就不滿足,後面剩餘元素不再檢測           

3、數組疊代——some

some()方法主要用來檢測數組中是否有元素滿足某一條件,如果有滿足條件的元素直接傳回true,剩餘元素不再進行檢測。

some()方法不會改變原數組。

           let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            let resultData = originData.some(function (value) {
                return value % 2 === 0 ? true : false;
            });
            console.log(resultData); //輸出true,因為第一項不滿足,但是第二項滿足條件,是以傳回true,後面剩餘元素不再檢測           

4、數組疊代——forEach

forEach()方法主要是周遊數組中的每一項,并将其傳遞給回調函數,它跟for循環周遊數組是一樣的。

           let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            originData.forEach(function (value) {
                console.log(value);
            });
            //依次輸出 1, 2, 3, 4, 5, 6, 7, 8, 9, 10           

5、數組疊代——map和filter

map()方法也會疊代數組,但是它會傳回一個新數組,這個新數組中的值是回調函數中每一次的執行結果。

map()方法不會改變原數組。

           let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            let resultData = originData.map(function (value) {
                return value % 2 === 0 ? true : false;
            });
            console.log(resultData); //輸出[false, true, false, true, false, true, false, true, false, true]           

filter()方法主要用來篩選數組,它也會傳回一個新數組,但是新數組中的值是符合回調函數條件的值。

filter()方法不會改變原數組。

           let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            let resultData = originData.filter(function (value) {
                return value % 2 === 0 ? true : false;
            });
            console.log(resultData); //輸出[2, 4, 6, 8, 10]           

6、數組疊代——reduce

reduce()方法的回調函數接收四個參數,但是平時我們僅用前兩個,分别表示數組中的前一個元素和目前元素。reduce()方法的回調函數其實就是一個累加器,它會将數組中的值從左至右進行計算(縮減),最終數組中的所有值會計算得到一個結果,然後它将這個結果傳回。是以reduce()方法非常适合求數組中所有元素的和。

reduce()方法不會改變原數組。

           let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            let resultData = originData.reduce(function (preValue, laterValue) {
                return preValue + laterValue;
            });
            console.log(resultData); //輸出55           

7、ES6和ES6+中新增的數組方法

除了以上的幾種方法之外,我們再來介紹幾種ES6和ES7中新增加的操作數組的方法。

@@iterator 傳回一個包含數組鍵值對的疊代器對象,可以通過同步調用得到數組元素的鍵值對
copyWithin 複制數組中一系列元素到同一數組指定的起始位置
entries 傳回包含數組所有鍵值對的 @@iterator
includes 如果數組中存在某個元素則傳回 true ,否則傳回 false 。E2016新增
find 根據回調函數給定的條件從數組中查找元素,如果找到則傳回該元素
findIndex 根據回調函數給定的條件從數組中查找元素,如果找到則傳回該元素在數組中的索引
fill 用靜态值填充數組
from 根據已有數組建立一個新數組
keys 傳回包含數組所有索引的 @@iterator
of 根據傳入的參數建立一個新數組
values 傳回包含數組中所有值的 @@iterator

下面我們還是來挑幾個常用的方法做一下介紹。

7.1、for……of循環疊代

JS中的數組循環除了for循環和forEach循環之外,在ES6中還提供了另一種循環方式,即for……of循環,下面來看下具體用法:

           let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            for (const n of originData) {
                console.log(n);
            }
            //依次輸出 1, 2, 3, 4, 5, 6, 7, 8, 9, 10           
7.2、@@iterator屬性

ES6在JS中的Array類中新增加了一個@@iterator屬性,這個屬性通過如下方法來使用:

           let originData = [1, 2, 3, 4, 5];
            let iterator = originData[Symbol.iterator]();
            console.log(iterator.next().value); //輸出1
            console.log(iterator.next().value); //輸出2
            console.log(iterator.next().value); //輸出3
            console.log(iterator.next().value); //輸出4
            console.log(iterator.next().value); //輸出5
            console.log(iterator.next().value); //輸出undefined
            console.log(iterator.next().value); //輸出undefined           

上述方法在iterator.next().value疊代完之後,後面的資料值都是undefined。除了上述的疊代方法之外,還可以通過下面的方式疊代裡面的資料:

           let originData = [1, 2, 3, 4, 5];
            let iterator = originData[Symbol.iterator]();
            for (const i of iterator) {
                console.log(i);
            }
            //輸出1, 2, 3, 4, 5           
7.3、entries、keys和values方法

entries()、keys()和values()三個方法都是ES6中新增的,為了擷取數組中的疊代器,用法如下:

           let originData = [1, 2, 3, 4];
            let entriesValue = originData.entries();
            console.log(entriesValue.next().value);
            console.log(entriesValue.next().value);
            console.log(entriesValue.next().value);
            console.log(entriesValue.next().value);
            console.log(entriesValue.next().value);
            console.log(entriesValue.next().value);
​
            let keysValue = originData.keys();
            console.log(keysValue.next());
            console.log(keysValue.next());
            console.log(keysValue.next());
            console.log(keysValue.next());
            console.log(keysValue.next());
            console.log(keysValue.next());
​
            let valValue = originData.values();
            console.log(valValue.next());
            console.log(valValue.next());
            console.log(valValue.next());
            console.log(valValue.next());
            console.log(valValue.next());
            console.log(valValue.next());           
【JS資料結構與算法】數組
7.4、from方法

from()方法會根據一個已有數組傳回一個新數組,此方法可以用來複制數組,也可以傳入第二個參數來篩選數組或計算數組,如下:

           let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            let resultData_01 = Array.from(originData);
            console.log(resultData_01); //輸出[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
​
            let resultData_02 = Array.from(originData, function (value) {
                return value % 2 === 0 ? value : false;
            });
            console.log(resultData_02); //輸出[false, 2, false, 4, false, 6, false, 8, false, 10]           
7.5、Array.of方法

Array.of()方法根據傳入的參數建立一個新數組。也可以用它來複制已有的數組,用法如下:

           let originData = Array.of(1, 2, 3);
            console.log(originData); //輸出[1, 2, 3]
​
            let resultData = Array.of(...originData);
            console.log(resultData); //輸出[1, 2, 3]           
7.6、fill方法

fill()方法用于填充資料,支援全部填充,指定位置填充。用法如下:

           let originData = [1, 2, 3, 4, 5];
            originData.fill(88);
            console.log(originData); //輸出[88, 88, 88, 88, 88]
​
            originData.fill(99, 2);
            console.log(originData); //輸出[88, 88, 99, 99, 99]
​
            originData.fill(77, 1, 3);
            console.log(originData); //輸出[88, 77, 77, 99, 99]           
7.7、copyWithin方法

copyWithin()方法主要是用來将數組中指定位置和個數的元素複制到原數組的指定位置,如下:

           let originData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
            originData.copyWithin(0, 3);
            console.log(originData); //輸出[4, 5, 6, 7, 8, 9, 10, 8, 9, 10]
            originData.copyWithin(0, 3, 5);
            console.log(originData); //輸出[7, 8, 6, 7, 8, 9, 10, 8, 9, 10]           

8、元素的排序

在介紹元素排序之前,先給大家介紹一個reverse()方法,這個方法會将我們數組中的元素反序輸出,使用方法如下:

           let originData = [1, 2, 3, 4, 5];
            console.log(originData.reverse()); //輸出[5, 4, 3, 2, 1]           

除了上述可以将數組元素反序的方法之外,JS數組還向我們提供了一個供元素排序的方法,叫做sort()方法,在這個方法中通過傳入一個自定義函數,數組元素會按照我們指定的順序進行排序輸出,如下:

           let originData = [3, 1, 2, 5, 4];
            originData.sort(function (a, b) {
                //實作降序
                return b - a;
            });
            console.log(originData); //輸出[5, 4, 3, 2, 1]           

9、元素搜尋

JS的數組為我們提供了indexOf()和lastIndexOf()兩個方法供我們在數組中查找元素,第一個方法傳回與參數比對的第一個元素的索引,第二個方法傳回與參數比對的最後一個元素的索引。除了這兩個方法之外,ES6和ES7中還增加了一些供數組查找的方法。

ES6新增find()和findIndex()方法。

ES7新增includes()方法。

以上各種方法的使用,如下:

           //元素搜尋
            let originData = [1, 2, 3, 4, 3, 3, 4];
​
            console.log(originData.indexOf(3)); //輸出2
            console.log(originData.lastIndexOf(3)); //輸出5
​
            let findValue = originData.find(function (value) {
                if (value % 2 === 0) {
                    return value;
                }
            });
            console.log(findValue); //輸出2
            let findIndexValue = originData.findIndex(function (value) {
                if (value % 2 === 0) {
                    return value;
                }
            });
            console.log(findIndexValue); //輸出1
​
            console.log(originData.includes(4)); //輸出true           

10、将元素輸出為字元串

JS的數組中還提供了兩個方法,可以将數組中的元素輸出為字元串,使用方法如下:

           //元素輸出為字元串
            let originData = [1, 2, 3, 4, 5];
            console.log(originData.toString()); //輸出1,2,3,4,5
            console.log(originData.join('-')); //輸出1-2-3-4-5           

JS類型數組

我們以上介紹的數組裡面是可以存儲任意類型資料的,是以JS裡的數組不是強類型的,但是我們可以用以下的方式聲明和定義一個強類型的數組,這就是類型數組。

類型數組 資料類型
Int8Array 8 位二進制補碼整數
Uint8Array 8 位無符号整數
Uint8ClampedArray
Int16Array 16位二進制補碼整數
Uint16Array 16位無符号整數
Int32Array 32位二進制補碼整數
Uint32Array 32位無符号整數
Float32Array 32 位 IEEE 浮點數
Float64Array 64 位 IEEE 浮點數

以上就是類型數組支援的資料類型,我們簡單來看下具體使用:

           //類型數組
            let typeArray = new Int32Array(5); //定義一個長度為5的整數數組
            typeArray[0] = 32.5; //指派一個浮點數
            typeArray[1] = 22;
            console.log(typeArray); //輸出[32, 22, 0, 0, 0]           

總結

本篇文章中我們簡單介紹了一下數組,包括數組的定義、具體的操作、二維數組和多元數組以及數組的元素增加和删除等。在JS中的數組其實和其他語言中的數組是不一樣的,是以我們在介紹其他資料結構之前先給大家介紹一下數組這個資料結構,後面的其他資料結構都是在數組基礎之上的,是以大家看完這篇文章後就可以接下來學習其他的資料結構了。我們下一篇給大家介紹一下JS中的另一個資料結構——棧。

繼續閱讀