JS对象数组按指定属性去重并合并另一属性值为数组的实现
解决方案
你当前的filter方案只能保留首次出现的条目,无法对后续重复条目的属性做合并,改用Map做临时存储即可实现需求:
适配当前场景的实现
function dedupeAndMergeUrl(keyFn, array) { const map = new Map() array.forEach(item => { const key = keyFn(item) if (!map.has(key)) { // 首次遇到对应key,拷贝对象并将url转为数组格式存储 map.set(key, { ...item, url: [item.url] }) } else { // 已存在同key条目,追加url到数组 map.get(key).url.push(item.url) // 如果需要避免url重复可以替换成下面的写法 // const existedItem = map.get(key) // if (!existedItem.url.includes(item.url)) existedItem.url.push(item.url) } }) // 将Map的值转为数组返回 return Array.from(map.values()) } // 调用方式和你原有逻辑一致 const dedupedArray = dedupeAndMergeUrl((x) => x.name, originalArray)
通用版实现(支持自定义合并属性)
/** * 按指定属性去重数组,同时合并指定字段为数组 * @param {Function} keyFn 生成去重key的方法 * @param {Array} array 原数组 * @param {String} mergeField 需要合并的属性名 * @param {Boolean} uniqueMergeField 合并后的数组是否要去重,默认false */ function dedupeAndMerge(keyFn, array, mergeField, uniqueMergeField = false) { const map = new Map() array.forEach(item => { const key = keyFn(item) if (!map.has(key)) { map.set(key, { ...item, [mergeField]: [item[mergeField]] }) } else { const target = map.get(key) const currentVal = item[mergeField] if (!uniqueMergeField || !target[mergeField].includes(currentVal)) { target[mergeField].push(currentVal) } } }) return Array.from(map.values()) } // 调用示例 const dedupedArray = dedupeAndMerge(x => x.name, originalArray, 'url', true)
注意事项
- 上述代码用对象扩展运算符
...做浅拷贝,如果你的对象包含深层嵌套属性,需要替换为深拷贝逻辑 - 重复条目的非合并属性(示例中的id、description)默认取首次出现的条目值,如果需要取最后一次出现的值,可在追加合并属性的同时,覆盖对应非合并属性即可
内容的提问来源于stack exchange,提问作者mheavers
相关产品推荐
相关产品推荐

