配列から重複を取り除く

配列の重複を消す最短の書き方は [...new Set(arr)] です。順序は保たれます。オブジェクトの配列では消えない理由と、その場合の書き方も載せています。

実行して検証済み処理系Node 22.22.3対応ES6難易度●●○○○目安8更新

答え

Set に入れて配列に戻します。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 3, 1, 2 ]
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
Set(2) { 'a', 'b' } 2

順序は保たれます。残るのは、それぞれの値が最初に現れた位置です。

なぜこれで消えるのか

Set同じ値を2つ持てない入れ物です。入れようとしても、すでにあれば無視されます。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 3, 1, 2 ]
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
-1 [ 1 ] [ NaN, 1 ]

[...set] は、その Set入れた順で配列に戻す書き方です。

別のやり方

書き方 計算量 オブジェクトの重複 NaN 向いている場面
[...new Set(arr)] O(n) 消えない 1つにまとまる ほぼ常にこれ
filter + indexOf O(n²) 消えない 全部残る 古い環境しか無いとき
Map にキーで入れる O(n) 消せる オブジェクトの配列

filter + indexOf

Set が使えない古い環境向けの書き方です。

javascript
const users = [
{ id: 1, name: 'あかり' },
{ id: 1, name: 'あかり' },
];

console.log([...new Set(users)].length);
console.log(users[0] === users[1]);
2 false
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ { id: 1, name: 'あかり(更新後)' }, { id: 2, name: 'ゆうと' } ]

自分より前に同じ値が無いものだけ残す」という意味です。 indexOf が毎回先頭から探すので、要素が増えると急に遅くなります

つまずきどころ

NaN は indexOf では消えない

indexOf=== で比べます。ところが NaN === NaNfalse なので、 indexOfNaN を見つけられません

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ { id: 1, name: 'あかり' }, { id: 2, name: 'ゆうと' } ]
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 1, 2 ] [ 1, 1, 2 ]

filter + indexOfNaN を全部落としましたindexOf-1 を返し、 -1 === i がどの位置でも成り立たないためです。

SetSameValueZero という比べ方を使うので、NaN 同士は同じとみなします。 だから NaN は1つだけ残ります。 比べ方が何種類あるのかは なぜ NaN === NaN は false なのか にまとめてあります。

数値が混ざる配列では Set を使ってください。

オブジェクトの配列では消えない

SetindexOf も、オブジェクトは参照で比べます。 中身が同じでも、別々に作ったオブジェクトは別物です。

見た目が同じでも消えません。何をもって「同じ」とするかを自分で決める必要があります。 参照とコピーの話は オブジェクトを結合する にもまとめてあります。

オブジェクトを id で1つにまとめる

Map はキーが重複すると上書きします。これを使います。

users.map(u => [u.id, u])[キー, 値] の組を作り、Map に入れています。 同じ id は上書きされるので、後から来たものが残ります

先に来たほうを残したいなら、すでにあるキーは入れないようにします。

reverse() を2回かけて入れ替える書き方もありますが、順序が直感と合わず間違えやすいので勧めません。has() で見てから入れるほうが、読んで分かります。

元の配列は変わらない

ここに出てきた書き方は、どれも新しい配列を作ります。元の配列はそのままです。

絞り込みの考え方そのものは filter() の記事にまとめてあります。

この記事の根拠

  1. Set Objects — ECMAScript® 2026 Language Specificationtc39.es
  2. Array.prototype.indexOf — ECMAScript® 2026 Language Specificationtc39.es
  3. Set — MDNdeveloper.mozilla.org

掲載しているコード例は、公開前に読み手が押したときに動くのと同じもので実行して出力を突き合わせています。結果はリポジトリに残しています。

このページの原文(Markdown)