数据去重的需求实际上像是lodash这些工具库已经有成熟完备的实现,并且可以成熟地运用于生产环境。但是这并不妨碍我们从思维拓展的角度出发,看看去重可以用几种思路去实现。本文主要和大家分享javascript数组去重的几种思路。
首先是常规的双层循环比对的思路实现
function doubleloopuniq(arr) {
let result = [];
for (let i = 0, len = arr.length, isexist; i < len; i++) {
// 定义一个变量表示当前元素在 result 中是否存在。
isexist = false;
for (let j = 0, rlen = result.length; j < rlen; j++) {
if (result[j] === arr[i]) {
// 依次对result 中的元素 和 原数组元素进行比对。
isexist = true;
break;
}
}
// 最后判断如果不存在,则将此元素插入result
!isexist && result.push(arr[i]);
}
return result;
}
借助 js内置的indexof 进行去重
function indexofuniq(arr) {
let result = [];
for (let i = 0, len = arr.length; i < len; i++) {
// 用indexof 简化了二层循环的流程
if (result.indexof(arr[i]) === -1) result.push(arr[i]);
}
return result;
}
排序后前后比对去重
function sortuniq(arr) {
let result = [], last;
// 这里解构是为了不对原数组产生副作用
[ ...arr ].sort().foreach(item => {
if (item != last) {
result.push(item);
last = item;
}
});
return result;
}
通过hashtable去重
function hashuniq(arr) {
let hashtable = arr.reduce((result, curr, index, array) => {
result[curr] = true;
return result;
}, {})
return object.keys(hashtable).map(item => parseint(item, 10));
}
es6 set一行代码实现去重
function tosetuniq(arr) {
return array.from(new set(arr));
}
splice 去重(直接操作数组本身,带副作用)
function inplaceuniq(arr) {
let idx = 0;
while (idx < arr.length) {
let compare = idx + 1;
while (compare < arr.length) {
if (arr[idx] == arr[compare]) {
arr.splice(compare, 1);
continue;
}
++compare
}
++idx;
}
return arr;
}
最后在nodejs下面简单跑个测试,看看哪个效率高~
let data = [];
for (var i = 0; i < 100000; i++) {
data.push(math.random())
}
// 实现一个性能测试的装饰器
function performancetest(fn, descript) {
var a = new date().gettime();
return function () {
fn.apply(this, [].slice.call(arguments, 0));
console.log(descript, new date().gettime() - a)
}
}
performancetest(hashuniq, "hashtable")(data)
performancetest(sortuniq, "sortuniq")(data)
performancetest(tosetuniq, "tosetuniq")(data)
performancetest(indexofuniq, "indexofuniq")(data)
performancetest(doubleloopuniq, "doubleloopuniq")(data)
performancetest(inplaceuniq, "inplaceuniq")(data)
结果如下
hashtable 168ms
sortuniq 332ms
tosetuniq 80ms
indexofuniq 4280ms
doubleloopuniq 13303ms
inplaceuniq 9977ms
延伸思考: 如果数组内的元素是对象该怎么去重呢?
既然是引用类型,那么不免会使用到deepequal,固然这种思路可以解答这道问题,但难免不够高效。
从上面的测试中也可见通过new set 和 hashtable 去重是最高效的。
所以毫无疑问,我们要基于这两种方式去改造,我想用的是hashtable,
另一方面,为了降低深度比较带来的耗时,我尝试用json.stringify 将引用类型转化为基本类型。
function collectionuniq(collection) {
let hashtable = {};
collection.foreach(item => {
hashtable[json.stringify(item)] = true;
})
return object.keys(hashtable).map(item => json.parse(item))
}
那么问题来了,我们都知道对象的属性是无序的,假如数据是这种情况,那就gg了。
let collection = [ { a: 1, b: 2, c: 3 }, { b: 2, c: 3, a: 1 } ]
有一种tohash的思路,在对这个数组进行一次基本的去重之后,为了保证准确,
先遍历json 字符串 =>
通过 charcodeat()拿到每个字符串 的 unicode 编码 =>
相加得到一个总数,最后再两两进行比较,数值相等的就是重复的,这样就达到去重的效果了。
function tohash(obj) {
let power = 1;
let res = 0;
const string = json.stringify(obj, null, 2);
for (let i = 0, l = string.length; i < l; i++) {
switch (string[i]) {
case '{':
power *= 2
break
case '}':
power /= 2
break
case ' ':
case '\n':
case '\r':
case '\t':
break
default:
res += string[i].charcodeat(0) * power
}
}
return res
}
这只是一个实现基本的思路,有很大的改进空间,为了减少hash碰撞的可能,可以对一些特殊字符进行权重的增减。
重点是保证碰撞的几率小到比中大奖还小就可以了。
相关推荐:
javascript数组去重的几种方法分享
php实现数组去重的方法代码
js简单实现数组去重的方法分析
以上就是实例详解javascript数组去重的几种思路的详细内容。