一、ES5 中數(shù)組操作方法
詳盡使用參看 MDN_Array
二衙伶、ES5+ 中數(shù)組操作方法
除了 flat 和 flatMap 方法詳解,其它詳解參看 ES6 數(shù)組給我們帶來哪些操作便利害碾?
flat()和flatMap()本質上就是是歸納(reduce) 與 合并(concat)的操作矢劲。
Array.prototype.flat()
flat() 方法會按照一個可指定的深度遞歸遍歷數(shù)組,并將所有元素與遍歷到的子數(shù)組中的元素合并為一個新數(shù)組返回慌随。
- flat()方法最基本的作用就是數(shù)組降維
var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
//使用 Infinity 作為深度芬沉,展開任意深度的嵌套數(shù)組
arr3.flat(Infinity);
// [1, 2, 3, 4, 5, 6]
- 其次躺同,還可以利用 flat() 方法的特性來去除數(shù)組的空項
var arr4 = [1, 2, , 4, 5];
arr4.flat();
// [1, 2, 4, 5]
具體可參看 MDN_Array.prototype.flat()
Array.prototype.flatMap()
flatMap() 方法首先使用映射函數(shù)映射每個元素,然后將結果壓縮成一個新數(shù)組丸逸。它與 map 和 深度值1的 flat 幾乎相同蹋艺,但 flatMap 通常在合并成一種方法的效率稍微高一些。 這里我們拿map方法與flatMap方法做一個比較椭员。
var arr1 = [1, 2, 3, 4];
arr1.map(x => [x * 2]);
// [[2], [4], [6], [8]]
arr1.flatMap(x => [x * 2]);
// [2, 4, 6, 8]
// 只會將 flatMap 中的函數(shù)返回的數(shù)組 “壓平” 一層
arr1.flatMap(x => [[x * 2]]);
// [[2], [4], [6], [8]]
具體參看 MDN_Array.prototype.flatMap()
三车海、數(shù)組操作方法對數(shù)組自身的影響
四、九種數(shù)組去重方法
測試數(shù)組去重時間代碼示例
const arr = [];
// 生成[0, 100000]之間的隨機數(shù)
for (let i = 0; i < 100000; i++) {
arr.push(0 + Math.floor((100000 - 0 + 1) * Math.random()))
}
// ...實現(xiàn)算法
console.time('test');
arr.unique();
console.timeEnd('test');
1隘击、雙重去重
基本思路:通過拿出一個元素和剩下的元素依次比較,如果全部不相等則證明此元素為唯一研铆。
Array.prototype.unique = function () {
const newArray = [];
let isRepeat;
for (let i = 0; i < this.length; i++) {
isRepeat = false;
for (let j = 0; j < newArray.length; j++) {
if (this[i] === newArray[j]) {
isRepeat = true;
break;
}
}
if (!isRepeat) {
newArray.push(this[i]);
}
}
return newArray;
}
測試時間:
test: 3032.134033203125ms
缺點:復雜度太高
2埋同、indexOf
基本思路:如果索引不是第一個索引,說明是重復值棵红。
Array.prototype.unique = function () {
const newArray = [];
this.forEach(item => {
if (newArray.indexOf(item) === -1) {
newArray.push(item);
}
});
return newArray;
}
測試時間:
test: 6951.115966796875ms
3凶赁、sort
基本思路:先對原數(shù)組進行排序,然后再進行元素比較逆甜。
Array.prototype.unique = function () {
const newArray = [];
this.sort();
for (let i = 0; i < this.length; i++) {
if (this[i] !== this[i + 1]) {
newArray.push(this[i]);
}
}
return newArray;
}
測試時間:
test: 72.129150390625ms
4虱肄、includes
基本思路:判斷新數(shù)組中是否含有已存在的項
Array.prototype.unique = function () {
const newArray = [];
this.forEach(item => {
if (!newArray.includes(item)) {
newArray.push(item);
}
});
return newArray;
}
測試時間:
test: 5378.988037109375ms
5、reduce
reduce() 方法接收一個函數(shù)作為累加器交煞,數(shù)組中的每個值(從左到右)開始縮減咏窿,最終計算為一個值
Array.prototype.unique = function () {
return this.sort().reduce((init, current) => {
if(init.length === 0 || init[init.length - 1] !== current){
init.push(current);
}
return init;
}, []);
}
測試時間:
test: 69.05908203125ms
更好的使用場景:對象數(shù)組中去掉重復的對象
6、對象鍵值對keys()
基本思路:利用了對象的key不可以重復的特性來進行去重素征。
Array.prototype.unique = function () {
const newArray = [];
const tmp = {};
for (let i = 0; i < this.length; i++) {
if (!tmp[typeof this[i] + this[i]]) {
tmp[typeof this[i] + this[i]] = 1;
newArray.push(this[i]);
}
}
return newArray;
}
測試時間:
test: 333.0009765625ms
更適合處理如對象這樣的復雜的數(shù)據(jù)類型
7集嵌、Map 數(shù)據(jù)結構
兩種針對簡單數(shù)據(jù)類型的去重:
方法一:
Array.prototype.unique = function () {
const newArray = [];
const tmp = new Map();
for(let i = 0; i < this.length; i++){
if(!tmp.get(this[i])){
tmp.set(this[i], 1);
newArray.push(this[i]);
}
}
return newArray;
}
方法二:
Array.prototype.unique = function () {
const tmp = new Map();
return this.filter(item => {
return !tmp.has(item) && tmp.set(item, 1);
})
}
分別的測試時間:
test: 53.268798828125ms
test: 41.73193359375ms
8、Set 數(shù)據(jù)結構
也有兩種簡單的數(shù)據(jù)類型去重的:
方法一:
Array.prototype.unique = function () {
const set = new Set(this);
return Array.from(set);
}
方法二:
Array.prototype.unique = function () {
return [...new Set(this)];
}
測試時間:
test: 17.760009765625ms
test: 19.72509765625ms
上面兩種方法只適用簡單的數(shù)據(jù)類型去重御毅,如果遇到一個比較復雜的對象數(shù)組根欧,就去重失敗,如下代碼示例:
let arr = [
{ name: 'a', num: 1},
{ name: 'b', num: 1},
{ name: 'c', num: 1},
{ name: 'd', num: 1},
{ name: 'a', num: 1},
{ name: 'a', num: 1},
{ name: 'a', num: 1}
]
function unique (arr) {
return [...new Set(arr)]
}
console.log(unique(arr)) // 結果為原數(shù)組端蛆,有興趣可以復制代碼試一下
因為 set 數(shù)據(jù)結構認為對象永不相等凤粗,即使是兩個空對象,在 set 結構內部也是不等的
如何解決呢今豆?
這里需要借助 JSON.stringfy() 和 JSON.parse() 序列化對象:
// ES6對象數(shù)組所有屬性去重,篩選每個數(shù)組項的字符
function unique(arr) {
const map = new Map()
return arr.filter( item => !map.has(JSON.stringify(item)) && map.set(JSON.stringify(item), 1))
}
function unique(arr) {
return [...new Set(arr.map(e => JSON.stringify(e)))].map(e => JSON.parse(e))
}
// 兩者出來的結果
[
{ name: 'a', num: 1},
{ name: 'b', num: 1},
{ name: 'c', num: 1},
{ name: 'd', num: 1}
]
9嫌拣、underscore.js 方法庫
測試代碼
_.uniq(arr);
測試時間
test: 3640.329833984375ms
總結
除了考慮時間復雜度外、性能之外晚凿,還要考慮數(shù)組元素的數(shù)據(jù)類型等問題權衡選擇出采用哪種算法亭罪,通過上面的幾個測試用例,可以看出利用 Set 和 Map 數(shù)據(jù)結構去重的效率會高一些歼秽。