假設(shè)現(xiàn)在有一個(gè)物件數(shù)組
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 然後保留各個(gè)id的最後一項(xiàng)
arr=[
{
id:1,
content:'a'
},{
id:2,
content:'c'
},{
id:3,
content:'g'
},{
id:4,
content:'h'
},
]
有什麼好一點(diǎn)的方法嘛。 。
const result = arr.reduce((r, t) => {
// 在結(jié)果中查找 index,
// 如果找到,更新該位置的對象引用
// 找到則加一個(gè)
var i = r.findIndex(m => m.id === t.id);
if (i >= 0) {
r[i] = t;
} else {
r.push(t);
}
return r;
}, []);
這裡有一個(gè)問題,findIndex
至少有兩個(gè)瀏覽器不支持,所以,如果不支持的話,只好自己寫一個(gè)
Array.prototype.findIndex = Array.prototype.findIndex || function(predicate) {
for (let i = 0; i < this.length; i++) {
if (predicate(this[i])) {
return i;
}
}
return -1;
};
因?yàn)?id 不是字串,所以使用 ES6 的 Map
類別。當(dāng)資料量大的時(shí)候,使用查找表,比在列表中線性查找,效率會有顯著的提升。
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;
其實(shí)也可以用物件來取代 map,至少在這個(gè)用例中不會有問題。因?yàn)闆]用 es6 特性,所以索性完全使用 es5 語法。程式碼結(jié)構(gòu)和邏輯跟上面那段一樣
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;
因?yàn)槭钦麛?shù) id,所以可以直接按這個(gè) id 放在陣列中。如果遇到相同 id,直接就替換了。如果 id 不連續(xù),最後需要把空元素過濾掉
var result = arr
.reduce(function(r, t) {
r[t.id] = t;
return r;
}, [])
.filter(function(t) { return t; });
這種解法還有個(gè)問題,不能保持原數(shù)組的元素順序。然後一定會有人想到,用 Map 的那個(gè)解法也可以把程式碼精減成類似的程式碼,而不需要搞那麼複雜,當(dāng)然它也同樣可能失去原有順序
const map = arr
.reduce((m, t) => {
m.set(t.id, t);
return m;
}, new Map());
const result = [...map.values()];
註:以上所有程式碼均實(shí)際運(yùn)行通過,運(yùn)行環(huán)境 Node v8.1.2
var result = arr.filter(function(val, index) {
/**
* 使用arr.slice(index + 1)獲取從當(dāng)前索引下一個(gè)元素到數(shù)組最后一個(gè)元素組成的數(shù)組
* 使用findIndex在當(dāng)前項(xiàng)的后面選項(xiàng)中查找是否有和當(dāng)前項(xiàng)id值相同的選項(xiàng)
*/
var index = arr.slice(index + 1).findIndex(function(item) {
return item.id === val.id;
});
// 如果為-1,則說明后面沒有同名id了,所以這一項(xiàng)可以返回
return index === -1;
});
console.log(result);
使用箭頭函數(shù)簡單如下:
var result = arr.filter((val, index) => arr.slice(index + 1).findIndex(item => item.id === val.id) === -1);
console.log(result);
這裡面已經(jīng)有很多答案了,不過沒有提到Array的內(nèi)建函數(shù)reduceRight,實(shí)際上題主的需求,要求保留相同id的最後一位,用reduceRight實(shí)現(xiàn)起來很方便。
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從你原數(shù)組尾端開始循環(huán)的,我這裡的初始值是個(gè)數(shù)組,r[0]用來存放id的Set,r[1]存放結(jié)果數(shù)組,如果Set裡沒有id,那就加這個(gè)id到Set,並且把這一項(xiàng)放在結(jié)果陣列的頭部。
最終很容易的實(shí)現(xiàn)了題主的需求,而且順序也能保證。
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
}
親測有效
參考一下
Array.from(arr.reduce((map, el) => map.set(el.id, el), new Map()).values())
你可以參考我部落格寫的,我部落格寫了8中方法。 http://alfierichou.top/2017/0...