数组的高级用法 (2)
前言
上篇,我们一起学些了去空值,生成随机数据和序列, 清空数组,数组浅拷贝等数组的高级用法,今天我们继续数组的奇妙之旅。
大家,动起来。
数组去重
非常主流的的Set配合数组去重。
var arr = ["苹果", "梨", 1,1,3, 3, undefined, {a: 1}]; var arr2 = Array.from(new Set(arr)); // ['苹果', '梨', 1, 3, undefined, {…}] 复制代码
咋眼一看,没问题,666。
对于引用类型,但是这个有一个很严重的问题,就是对重的定义?
function uniqueArray(arr){ return Array.from(new Set(arr)) } var arr = [{a:1}, {a:1}]; console.log(uniqueArray(arr)); // [{a:1}, {a:1}] var obj1 = {a:1} var arr2 = [obj1, obj1]; console.log(uniqueArray(arr2)); // [{a:1}] 复制代码
从例子中可见看得出Array.from(new Set(arr))
对同引用 的对象是有用的,但是对属性键和值都相同的对象却没有作用的,比如你从接口获得的数据。
有些前端就要说了,这后端做就行,我微微一笑,你看迷人不?
多义真的对引用类型去重,用Set是满足不了的,这个时候,有请Array.prototype.filter
:
function uniqueArray(arr = [], key){ const keyValues = new Set(); let val; return arr.filter(obj=> { val = obj[key]; if(keyValues.has(val)){ return false; } keyValues.add(val); return true; }) } var arr = [{a:1}, {a:1}]; console.log(uniqueArray(arr)); // [{a:1}] 复制代码
上面的原理就是通过一个唯一的键值来过滤,不错不错,看起来不错,但是要多个值才能确认唯一的项呢?
亲, 基于上面的代码,你可以的。
求交集
网上常见的是这样:
const arr1 = [0, 1, 2] const arr2 = [3, 2, 0] const values = [...new Set(arr1)].filter(item =>arr2 .includes(item)) console.log(values) // [0, 2] 复制代码
不通用,我们抽象一下:
function intersectSet(arr1, arr2){ return [...new Set(arr1)].filter(item =>arr2 .includes(item)) } intersectSet(arr1, arr2) // [0, 2] 复制代码
咋眼一看,也没问题,这有两个问题:
引用类型和相同的判断
性能问题 每次includes,这个是不是有点费资源。
我们改进一波, 假设对象都是有效的对象
// 引用类型 function intersect(arr1, arr2, key){ const map = new Map(); arr1.forEach(val=> map.set(val[key])) return arr2.filter(val=> { return map.has(val[key]); }); } // 原始数据类型 function intersectBase(arr1, arr2){ const map = new Map(); arr1.forEach(val=> map.set(val)) return arr2.filter(val=> { return map.has(val); }); } var arr1 = [{p:0}, {p:1}, {p:2}] var arr2 = [{p:3}, {p:2}, {p:1}] intersect(arr1, arr2, "p"); // [{p:2, p: 1}] const arr1 = [0, 1, 2] const arr2 = [3, 2, 0] intersectBase(arr1,arr2 ); 复制代码
这里大家可能有人会说,这性能会高一些吗?,那我们一起测试一把。
function createData(length){ return Array.from({length}, (val, i)=> { return ~~(Math.random()* length) }) } var data1 = createData(10000); var data2 = createData(10000); console.time("intersectSet"); intersectSet(data1, data2); console.timeEnd("intersectSet"); console.time("intersectBase"); intersectBase(data1, data2); console.timeEnd("intersectBase"); 复制代码
数组长度 | intersectSet (ms) | intersectBase (ms) |
---|---|---|
1000 | 0.6 | 0.2 |
10000 | 51.2 | 2.7 |
100000 | 4973.8 | 22.1 |
可以看到,数据越多,使用Set + Array.prototype.includes
相对Map性能越差,这个是和数据结构挂钩的,平时可能不需要那么多注意,但是,这些基本知识还是要了解的。
小结
今天学习了数组去重和求交集。 今天你收获了吗?
作者:一花一个世界
链接:https://juejin.cn/post/7015373530757873694