JavaScript取出”陣列-物件“重複/不重複值的方法

昨天在 FB 社團看到有人提問:

1
2
3
4
5
6
let arr = [
{ name: "alex", value: 10 },
{ name: "alex", value: 20 },
{ name: "tom", value: 30 },
{ name: "tom", value: 40 }
];

想變成

1
2
3
4
let arr = [
{ name: "alex", value: 10 },
{ name: "tom", value: 30 }
];

想了一陣子想到用Set&Filter來處理..

去除某物件屬性重複值

針對題目的需求是只要重複name的第一筆資料,
透過Set來達到去重複的功能並透過filter來獲取結果陣列:

1
2
3
4
5
6
7
8
9
10
const arr = [
{name:'alex',value:10},
{name:'alex',value:20},
{name:'tom',value:30},
{name:'tom',value:40}
];
const set = new Set();
const result = arr.filter(item => !set.has(item.name) ? set.add(item.name) : false);
console.log(result);
// [{name: "alex", value: 10}, {name: "tom", value: 30}]

第一步先建立一個set來當篩選的容器,
filter裡頭判斷,如果set裡面沒有循環到的name,
就新增進去,再新增的同時因為filter的特性是會把retun true的內容回傳為新的陣列,
箭頭函示不加大括號的情況下會等同於return,在這個情境下等於回傳了一個動作(此動作是成立的,是true)。

去除重複的物件

如果要針對整個陣列物件中去除重複物件的話可以透過JSON.stringify來做:

1
2
3
4
5
6
7
8
9
const arr = [
{name:'a', value:10},
{name:'a', value:20},
{name:'a', value:20},
{name:'b', value:30},
];
const result = [...new Set(arr.map(item => JSON.stringify(item)))].map(item => JSON.parse(item));
console.log(result);
// [{name: "a", value: 10}, {name: "a", value: 20}, {name: "b", value: 30}]

弄成一行看起來好像比較厲害(?)XD

因為物件跟物件之間無法比較,所以想法是透過轉字串來比較,
第一步先使用new Set並透過mapJSON.stringify把每一個陣列內的物件轉為字串,
再透過展開運算符[...]來把剛才Set的結果轉為陣列,
最後再用一次map把裡面的物件字串透過JSON.parse再轉回物件。

取得重複的物件

剛才都是去除重複,那如果是要抓出重複的物件有哪些呢?
把邏輯反轉過來:

1
2
3
4
5
6
7
8
9
10
11
12
13
const arr = [
{name:'a', value:10},
{name:'a', value:20},
{name:'a', value:20},
{name:'b', value:30},
{name:'b', value:40},
{name:'b', value:40}
];
const set = new Set();
const result = arr.filter(item => set.has(JSON.stringify(item)) ? true : (set.add(JSON.stringify(item)), false));
console.log(result);
//[{name: "a", value: 20}, {name: "b", value: 40}]

這裡跟前面的差不多道理,比較特別在三元運算子的部分,
同前面提到的,filter的特性是會將return true的內容加入,
所以如果單純寫

1
set.has(JSON.stringify(item)) ? true : set.add(JSON.stringify(item))

這樣的話也會被新增進去,因為set.add(JSON.stringify(item))也是個true的動作,
所以使用(set.add(JSON.stringify(item)), false)來讓新增動作執行後,
再回傳false阻止filter的新增。

其實寫清楚一點就是下面這樣,不過就是會想試試一行寫完的方法XD

1
2
3
4
5
6
7
const result = arr.filter(item => {
if (set.has(JSON.stringify(item))) {
return true;
} else {
set.add(JSON.stringify(item));
}
});

其他

以上都是自己邊試邊理解的,如果有錯誤或更好的寫法也請再告知:D!

陣列的做法紀錄

JavaScript取出陣列重複/不重複值的方法