如果一个数组只包含原始变量,我们可以使用filter
和indexOf
方法将其去重:
var deduped = [ 1, 1, 'a', 'a' ].filter(function (el, i, arr) {
return arr.indexOf(el) === i;
});
console.log(deduped); // [ 1, 'a' ]
我们可以使用箭头函数使写法更简明:
var deduped = [ 1, 1, 'a', 'a' ].filter( (el, i, arr) => arr.indexOf(el) === i);
console.log(deduped); // [ 1, 'a' ]
但是根据Sets和from
方法的介绍,我们可以更简明的实现。
var deduped = Array.from( new Set([ 1, 1, 'a', 'a' ]) );
console.log(deduped); // [ 1, 'a' ]
当元素为对象(Object)时,我们就不能用这种办法了, 因为对象存储的是引用而原始变量存储的是值。
1 === 1 // true
'a' === 'a' // true
{ a: 1 } === { a: 1 } // false
因此我们需要改变一下我们的实现方法,使用哈希表。
function dedup(arr) {
var hashTable = {};
return arr.filter(function (el) {
var key = JSON.stringify(el);
var match = Boolean(hashTable[key]);
return (match ? false : hashTable[key] = true);
});
}
var deduped = dedup([
{ a: 1 },
{ a: 1 },
[ 1, 2 ],
[ 1, 2 ]
]);
console.log(deduped); // [ {a: 1}, [1, 2] ]
因为哈希表在Javascript里是一个简单的Object
,它的key
永远是String
类型。这意味着我们不能区分字符串和数字表示的相同的值,如1
和'1'
。
var hashTable = {};
hashTable[1] = true;
hashTable['1'] = true;
console.log(hashTable); // { '1': true }
然而,因为我们使用的JSON.stringify
,String
类型的key
将会被存储为一个字符串值,这样hashTable
的key
就唯一了。
var hashTable = {};
hashTable[JSON.stringify(1)] = true;
hashTable[JSON.stringify('1')] = true;
console.log(hashTable); // { '1': true, '\'1\'': true }
这意味着相同的值,但不同类型的元素,将以原来的格式保留。
var deduped = dedup([
{ a: 1 },
{ a: 1 },
[ 1, 2 ],
[ 1, 2 ],
1,
1,
'1',
'1'
]);
console.log(deduped); // [ {a: 1}, [1, 2], 1, '1' ]
filter
indexOf
from
JSON.stringify
40 天前