オブジェクトの配列から 特定プロパティの値が重複した要素を取り除く方法
Typescriptで書いているので、JSで実行する場合は型宣言を消すこと。
const users = [
{
name : "tanaka",
age : 23,
},
{
name : "yamada",
age : 45,
},
{
name : "tanaka",
age : 23,
},
{
name : "suzuki",
age : 56,
},
{
name : "takahashi",
age : 23,
},
{
name : "suzuki",
age : 56,
},
]
// 上の配列から 以下の配列を得たい
const expectation = [
{ name: 'tanaka', age: 23 },
{ name: 'yamada', age: 45 },
{ name: 'suzuki', age: 56 },
{ name: 'takahashi', age: 23 }
]
suzuki と tanaka が 重複しているのでそれを取り除いた配列を得たいという需要に応えるものです。
メモを作って重複を取り除く実装(+Mapをつかったテクニック)です。
※ nameはアプリケーション仕様でユニークキーであるという前提です。
配列をメモとして使うパターン 対象が少ない場合は場合は問題ない(線形走査 なので遅い
const nameMemo : string[] = []
const uniqueUsers1 = users.filter((user) => {
if(!nameMemo.includes(user.name)){
nameMemo.push(user.name)
return true
}
return false
})
console.log(uniqueUsers1)
Setを使うパターン 対象が非常に多い場合
const nameMemoSet : Set<string> = new Set()
const uniqueUsers2 = users.filter((user) => {
if(!nameMemoSet.has(user.name)){
nameMemoSet.add(user.name)
return true
}
return false
})
console.log(uniqueUsers2)
メモのスコープが広い事が気になる場合は 即時実行関数式(IIFE)にすると良い。
配列パターン
const uniqueUsers3 = users.filter((memo => (user:typeof users[number]) => {
if(!memo.includes(user.name)){
memo.push(user.name)
return true
}
return false
})([] as string[]))
console.log(uniqueUsers3)
Setパターン
const uniqueUsers4 = users.filter((memo => (user:typeof users[number]) => {
if(!memo.has(user.name)){
memo.add(user.name)
return true
}
return false
})(new Set<string>()))
console.log(uniqueUsers4)
コードは書いていないが、ユニークなキーがオブジェクトのキーになれる値であればObjectのキーをメモにする事もできる。
Mapを使った方法、Mapのキーが重複出来ないことを利用している。
一見しただけだと要素を絞り込んでいるように見えないため好みが分かれそう。
const uniqueUsers5 = [...( new Map<string,typeof users[number]>( users.map(user => [user.name , user ]) )).values()]
console.log(uniqueUsers5)