JavaScript数组键值去重方法
使用 filter
和 Map
根据键值去重
我来详细解释方法2,这是一种高效且简洁的数组去重方法,特别适合根据对象中的某个键值进行去重操作。
完整代码
function uniqueByKey(arr, key) {return [...new Map(arr.map(item => [item[key], item])).values()];
}
分步解析
让我们分解这个方法的每个步骤:
arr.map(item => [item[key], item])
遍历原始数组,为每个元素创建一个新数组
新数组的第一个元素是对象的键值(
item[key]
)第二个元素是对象本身(
item
)例如,对于
{id: 1, name: 'John'}
,当 key 是 'id' 时,会变成[1, {id: 1, name: 'John'}]
new Map()
将上一步生成的数组对传递给
Map
构造函数Map
对象会自动处理键值对,当有相同的键时,后面的值会覆盖前面的值这是去重的关键步骤,因为
Map
的键必须是唯一的
.values()
获取
Map
中所有的值(即原始对象)这会返回一个
MapIterator
对象
[... ]
使用扩展运算符将
MapIterator
转换为普通数组
为什么这个方法有效?
Map
对象的特点是键必须是唯一的当我们把对象的键值作为
Map
的键,对象本身作为值时:如果遇到相同的键值,后面的对象会覆盖前面的对象
最终
Map
中只保留每个键值的最后一个对象
通过
values()
方法,我们只获取对象部分,忽略键
示例演示
假设我们有如下数组:
const data = [{id: 1, name: 'John'},{id: 2, name: 'Jane'},{id: 1, name: 'Johnny'}, // 重复的 id:1{id: 3, name: 'Alice'}
];
执行步骤:
data.map(item => [item['id'], item])
生成:[[1, {id: 1, name: 'John'}],[2, {id: 2, name: 'Jane'}],[1, {id: 1, name: 'Johnny'}],[3, {id: 3, name: 'Alice'}] ]
new Map()
处理后:Map {1 => {id: 1, name: 'Johnny'}, // 后面的覆盖了前面的2 => {id: 2, name: 'Jane'},3 => {id: 3, name: 'Alice'} }
.values()
获取:MapIterator {{id: 1, name: 'Johnny'},{id: 2, name: 'Jane'},{id: 3, name: 'Alice'} }
[... ]
转换为数组:[{id: 1, name: 'Johnny'},{id: 2, name: 'Jane'},{id: 3, name: 'Alice'} ]
注意事项
保留最后一个重复项:这个方法会保留最后一个遇到的重复键值对象,而不是第一个
性能优势:对于大型数组,这种方法通常比其他方法(如使用
filter
+find
)性能更好,因为Map
的查找操作是 O(1) 复杂度键值类型:键值可以是任何类型,但会被
Map
转换为字符串形式进行比较
如果需要保留第一个遇到的重复项而不是最后一个,可以先将数组反转,处理后再反转回来:
function uniqueByKeyKeepFirst(arr, key) {return [...new Map([...arr].reverse().map(item => [item[key], item])).values()].reverse();
}