---
type: how-to
language: javascript
slug: array/remove-duplicates
title: "配列から重複を取り除く"
title_tag: "JavaScript 配列の重複を削除する — Set が最短。落とし穴も"
summary: >
  配列の重複を消す最短の書き方は [...new Set(arr)] です。
  順序は保たれます。オブジェクトの配列では消えない理由と、その場合の書き方も載せています。
description: >
  Set を使うのが最短です。オブジェクトの配列で重複が消えない理由、キーを決めて重複を除く書き方、NaN が1つにまとまる理由まで、実行して確かめられます。
status: published
difficulty: 2
minutes: 8

versions:
  verified: "Node 22.22.3"
  since: "ES6"
  deprecated: null
  removed: null

sources:
  - title: "Set Objects — ECMAScript® 2026 Language Specification"
    url: "https://tc39.es/ecma262/#sec-set-objects"
  - title: "Array.prototype.indexOf — ECMAScript® 2026 Language Specification"
    url: "https://tc39.es/ecma262/#sec-array.prototype.indexof"
  - title: "Set — MDN"
    url: "https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Set"

terms: [Set, SameValueZero, 参照, スプレッド構文]

links:
  related:
    - javascript/reference/array/filter
    - javascript/why/nan-equality
    - javascript/how-to/object/merge
    - javascript/how-to/array/compare

content_updated_at: 2026-09-07
published_at: 2026-09-07
---

## 答え

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

```js run
const arr = [3, 1, 2, 2, 3, 3];

console.log([...new Set(arr)]);
```
```output
[ 3, 1, 2 ]
```

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

## なぜこれで消えるのか

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

```js run
const set = new Set();

set.add('a');
set.add('a');
set.add('b');

console.log(set);
console.log(set.size);
```
```output
Set(2) { 'a', 'b' }
2
```

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

## 別のやり方

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

### filter + indexOf

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

```js run
const arr = [3, 1, 2, 2, 3, 3];

console.log(arr.filter((v, i) => arr.indexOf(v) === i));
```
```output
[ 3, 1, 2 ]
```

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

## つまずきどころ

### NaN は indexOf では消えない

`indexOf` は `===` で比べます。ところが [code:NaN === NaN] は [bad:false] なので、
`indexOf` は [key:NaN を見つけられません]。

```js run
const arr = [NaN, NaN, 1, 1];

console.log(arr.indexOf(NaN));
console.log(arr.filter((v, i) => arr.indexOf(v) === i));
console.log([...new Set(arr)]);
```
```output
-1
[ 1 ]
[ NaN, 1 ]
```

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

`Set` は [type:SameValueZero] という比べ方を使うので、[key:NaN 同士は同じとみなします]。
だから `NaN` は1つだけ残ります。
比べ方が何種類あるのかは
[なぜ NaN === NaN は false なのか](/ja/javascript/why/nan-equality/) にまとめてあります。

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

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

`Set` も `indexOf` も、オブジェクトは[key:参照]で比べます。
中身が同じでも、別々に作ったオブジェクトは[bad:別物]です。

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

console.log([...new Set(users)].length);
console.log(users[0] === users[1]);
```
```output
2
false
```

見た目が同じでも消えません。**何をもって「同じ」とするかを自分で決める**必要があります。
参照とコピーの話は
[オブジェクトを結合する](/ja/javascript/how-to/object/merge/) にもまとめてあります。

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

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

```js run
const users = [
  { id: 1, name: 'あかり' },
  { id: 2, name: 'ゆうと' },
  { id: 1, name: 'あかり（更新後）' },
];

const unique = [...new Map(users.map(u => [u.id, u])).values()];

console.log(unique);
```
```output
[ { id: 1, name: 'あかり（更新後）' }, { id: 2, name: 'ゆうと' } ]
```

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

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

```js run
const users = [
  { id: 1, name: 'あかり' },
  { id: 2, name: 'ゆうと' },
  { id: 1, name: 'あかり（更新後）' },
];

const map = new Map();

for (const u of users) {
  if (!map.has(u.id)) map.set(u.id, u);
}

console.log([...map.values()]);
```
```output
[ { id: 1, name: 'あかり' }, { id: 2, name: 'ゆうと' } ]
```

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

## 元の配列は変わらない

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

```js run
const arr = [1, 1, 2];

const unique = [...new Set(arr)];

console.log(unique);
console.log(arr);
```
```output
[ 1, 2 ]
[ 1, 1, 2 ]
```

絞り込みの考え方そのものは
[filter()](/ja/javascript/reference/array/filter/) の記事にまとめてあります。
