點燈坊

失くすものさえない今が強くなるチャンスよ

如何移除 Array 中重複部分 ?

Sam Xiao's Avatar 2019-07-24

實務上常會遇到 Array 雖有重複資料,但我們並不希望顯示重複部分,這個常見需求,該如何使用 ECMAScript 實現呢 ?

Version

macOS Mojave 10.14.5
VS Code 1.36.1
Quokka 1.0.236
ECMAScript 2015
Ramda 0.26.1

Set

let data = [1, 2, 3, 1];

let uniq = arr => [...new Set(arr)];

uniq(data); // ?

若使用 ES6,對於處理 primitive 重複,最簡單就是使用 set。

Set 的本意就是儲存 不重複 的 object,因此 array 傳入後,會自動移除重複部分,最後再使用 spread operator 展開成為新 array 回傳。

unique000

Array.from()

let data = [1, 2, 3, 1];

let uniq = arr => Array.from(new Set(arr));

uniq(data); // ?

也可使用 Array.from() 將 set 轉成 array。

unique003

Ramda

import { uniq } from 'ramda';

let data = [1, 2, 3, 1];

uniq(data); // ?

Ramda 已經提供 uniq(),可直接使用。

unique001

Object

import { uniq } from 'ramda';

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 },
  { title: 'FP in JavaScript', price: 100 }
];

console.dir(uniq(data));

若 array 內是 object,則無法使用 set,因為 set 比較的是 object 的 reference,僅管 property 都相同,但 reference 還是不同,因此 set 視為不重複。

但 Ramda 的 uniq() 的判斷依據是 equals(),而 equals() 比較的是 property 的 value,因此 property 相同就視為重複。

Ramda 的 uniq() 無論 primitive 或 object 都適用

unique002

Conclusion

  • 若不使用 Ramda,則 set 是簡單的寫法,唯 set 僅對 primitive 有效,對 object 無效
  • Set 可搭配 spread operator 或 Array.from()
  • Ramda 的 uniq() 是最通用解法,無論是 primitive 或 object 都適用

Reference

Bret Cameron, 12 JavaScript Tricks You Won’t Find in Most Tutorials
Ramda, uniq()