假设现在有一个对象数组
arr=[
{
id:1,
content:'a'
},{
id:2,
content:'b'
},{
id:2,
content:'c'
},{
id:3,
content:'d'
},{
id:3,
content:'e'
},{
id:3,
content:'f'
},{
id:3,
content:'g'
},{
id:4,
content:'h'
},
]
我想去掉相同的id 然后保留各个id的最后一项
arr=[
{
id:1,
content:'a'
},{
id:2,
content:'c'
},{
id:3,
content:'g'
},{
id:4,
content:'h'
},
]
有什么好一点的方法嘛。。
漂亮男人2017-06-28 09:26:12
const result = arr.reduce((r, t) => {
// 在结果中查找 index,
// 如果找到,更新该位置的对象引用
// 找到则加一个
var i = r.findIndex(m => m.id === t.id);
if (i >= 0) {
r[i] = t;
} else {
r.push(t);
}
return r;
}, []);
这里有一个问题,findIndex
至少有两个浏览器不支持,所以,如果不支持的话,只好自己写一个
Array.prototype.findIndex = Array.prototype.findIndex || function(predicate) {
for (let i = 0; i < this.length; i++) {
if (predicate(this[i])) {
return i;
}
}
return -1;
};
因为 id 不是字符串,所以使用 ES6 的 Map
类。当数据量大的时候,使用查找表,比在列表中线性查找,效率会有显着的提升。
const result = arr
.reduce((m, t) => {
const { map, list } = m;
var index = map.get(t.id);
if (index >= 0) {
list[index] = t;
} else {
map.set(t.id, list.length);
list.push(t);
}
return m;
}, {
map: new Map(),
list: []
})
.list;
其实也可以用对象来代替 map,至少在这个用例中不会有问题。因为没用 es6 特性,索性完全使用 es5 语法。代码结构和逻辑与上面那段一样
var result = arr
.reduce(function(m, t) {
var index = m.map[t.id];
if (index >= 0) {
m.list[index] = t;
} else {
m.map[t.id] = m.list.length;
m.list.push(t);
}
return m;
}, {
map: {},
list: []
})
.list;
因为是整数 id,所以可以直接按这个 id 放在数组中。如果遇到相同 id,直接就替换了。如果 id 不连续,最后需要把空元素过滤掉
var result = arr
.reduce(function(r, t) {
r[t.id] = t;
return r;
}, [])
.filter(function(t) { return t; });
这种解法还有个问题,不能保持原数组的元素顺序。然后肯定会有人想到,用 Map 的那个解法也可以把代码精减成类似的代码,而不需要搞那么复杂,当然它也同样可能失去原有顺序
const map = arr
.reduce((m, t) => {
m.set(t.id, t);
return m;
}, new Map());
const result = [...map.values()];
注:以上所有代码均实际运行通过,运行环境 Node v8.1.2
某草草2017-06-28 09:26:12
var result = arr.filter(function(val, index) {
/**
* 使用arr.slice(index + 1)获取从当前索引下一个元素到数组最后一个元素组成的数组
* 使用findIndex在当前项的后面选项中查找是否有和当前项id值相同的选项
*/
var index = arr.slice(index + 1).findIndex(function(item) {
return item.id === val.id;
});
// 如果为-1,则说明后面没有同名id了,所以这一项可以返回
return index === -1;
});
console.log(result);
使用箭头函数简化如下:
var result = arr.filter((val, index) => arr.slice(index + 1).findIndex(item => item.id === val.id) === -1);
console.log(result);
仅有的幸福2017-06-28 09:26:12
这里面已经有很多答案了,不过没有提到Array的内置函数reduceRight,实际上题主的需求,要求保留相同id的最后一位,用reduceRight实现起来很方便。
arr.reduceRight((r,v)=>{
if(!r[0].has(v.id)) r[0].add(v.id) && r[1].unshift(v)
return r
},[new Set,[]])[1]
reduceRight从你原数组尾部开始循环的,我这里的初始值是个数组,r[0]用来存放id的Set,r[1]存放结果数组,如果Set里没有id,那么就添加这个id到Set,并且把这一项放在结果数组的头部。
最终很容易的实现了题主的需求,而且顺序也能保证。
曾经蜡笔没有小新2017-06-28 09:26:12
function uniq(arr) {
var idArr = [],arr2 = []
for (var i = 0, len = arr.length; i < len; i++) {
if (arr[i].id in idArr) {
arr2.pop()
arr2.push(arr[i])
} else {
idArr.push(arr[i].id)
arr2.push(arr[i])
}
}
return arr2
}
亲测有效
天蓬老师2017-06-28 09:26:12
参考一下
Array.from(arr.reduce((map, el) => map.set(el.id, el), new Map()).values())