【Javascript入門】Set オブジェクトを使って重複しない配列を作る

今回は、ES6から使うことが出来る「Set オブジェクト」について紹介します。

Set オブジェクトは、超簡単に説明すると「重複がない配列」を作ることが出来ます!

前半戦では、Set オブジェクトを実際に使ってみます。
基本的な書き方を学んでいく感じですね!

後半戦では、Set オブジェクトの活用例を紹介します!
こんな感じ。

  • 応募者一覧の実装
  • 抽選機能の実装

では、始めましょう!!

set オブジェクト使ってみよう【前半戦】

set オブジェクトの宣言

// set オブジェクトの宣言
const set = new Set();

// 初期値を持たせることも出来る
const set2 = new Set([10, 20, 30]);

Set を使うときは、new Set();でインスタンスを生成してあげます。
ちなみに、Set オブジェクトはClassで作られています。

Class構文について、分からない方は ↓↓ を読んでみると理解が深まると思います!
※Classが良く分からなくても読み進めちゃってOKです!
class構文の使い方・書き方が分かるようになる方法!

また、Set オブジェクトは初期値を持たせることも出来ます。
既に定義されている配列を Set オブジェクトで扱いたい場合に使います!

もし、初期値の配列内に重複する値があれば、Set オブジェクトになった瞬間に重複が無くなります。

// 重複アリの配列
const arr = [ 10, 20, 30, 20 ];

// 重複している「20」が1つになってる
const set2 = new Set(arr);  //  [ 10, 20, 30 ]

値の追加(add)

const set = new Set();

// 値の追加(add)
set.add(10);  //  [ 10 ]

// メソッドチェーンも可能
set.add(10).add(20);  //  [ 10, 20 ]

Set で作った配列に値を追加したい場合は.add()を使います。

また、set.add(10).add(20);のように . (ドット)で繋げることも出来ます。
こうして繋げることで、連続で処理を行うことが出来ます!
※俗にいう「メソッドチェーン」ってヤツですね
JavaScriptのメソッドチェーンの使い方を現役エンジニアが解説【初心者向け】 | TechAcademyマガジン

値を削除(delete)

const set = new Set([10, 20, 30]);

// 値を削除(delete)
set.delete(10);  //  [ 20, 30 ]

// 値をすべて削除(clear)
set.clear();  //  [  ]

Set オブジェクトの値を削除するときは.delete()を使います。
もし、すべての値を削除する場合は、.clear()を使ってあげればOKです。

指定した値が存在するかを確認(has)

const set = new Set([10, 20, 30]);

// 指定した値が存在するかを確認(has)
set.has(10);  //  true
set.has(100);  //  false

配列内に指定した値が存在しているかどうかを判定するためには.has()を使用します。

要素の個数を取得(size)

const set = new Set([10, 20, 30]);

// 要素の個数を取得(size)
const set_size = set.size;  //  3

個数を調べたいときは.sizeを使用します。
個数を取得する場合は、メソッドではないので()は必要ないですね!

通常の配列でも()になってないので、必要かどうか迷ったら.lengthを思い出すと良いかもしれない。

値を配列形式で取得(values)

// set オブジェクトの宣言
const set = new Set([10, 20, 30]);

// 値を配列形式で取得(values)
const arr = set.values();  //  [ 10, 20, 30 ]

Set オブジェクトではなく、配列として扱いたい場合は、.values()を使います。
例えば、配列の時に使える、filter()とかmap()reduce()などを使いたい場合に活躍しそうですね!

各値に対して何か処理をする(forEach)

const set = new Set([10, 20, 30]);

// 各値に対して何か処理をする(forEach)
set.forEach(() => {
  // ここに処理を書く
});

// for - of も使える!
for ( const value of set ) {
  //  ここに処理を書く
}

Set オブジェクトの中身を使って、何か処理をしたい場合はforEach()を使います。
ちなみに、配列をループすることが出来るfor-ofも使うことが出来ます!

基本的にどちらを使ってもOKです。
Setfor-ofも同じES6なので、for-ofの方を使ってあげた方がイケてるかもですね!!

業務でも使える set オブジェクトの活用例【後半戦】

前半戦、お疲れさまでした!!
この辺で、ちょっとコーヒー休憩でもどうぞ!

後半では、Set オブジェクトの活用術を紹介していきます。

  • 応募者一覧の実装
  • 抽選機能の実装

応募者一覧をカンタンに実装

今回は、応募者一覧を出力する想定でコードを実装してみました!
とあるキャンペーンがあって、そのキャンペーンに誰が応募したのかを確認する感じですね。
キャンペーンはひとりで数口応募できるものとします。

まずは、完成系

const data = [
  { id: 12, name: '鈴木太郎' },
  { id: 15, name: '佐藤次郎' },
  { id: 12, name: '鈴木太郎' },
  { id: 3, name: '北島三郎' },
  { id: 15, name: '佐藤次郎' },
];

// 名前一覧の配列を生成
const map_arr = data.map(data => data.name);
// Set オブジェクトで重複している名前を削除
const name_list = new Set(map_arr);

console.log(name_list);

解説していきます!

まず、APIなどでデータベースから、こんな感じのデータを取得してきたとします。

const data = [
  { id: 12, name: '鈴木太郎' },
  { id: 15, name: '佐藤次郎' },
  { id: 12, name: '鈴木太郎' },
  { id: 3, name: '北島三郎' },
  { id: 15, name: '佐藤次郎' },
];

Set オブジェクトは配列しか対応できないので、名前のみを格納した配列を作ります。

// 名前一覧の配列を生成
const map_arr = data.map(data => data.name);

配列を生成するために、今回は.map()を使用しています。
map_arrを出力するとこんな感じの配列になります。

0: "鈴木太郎"
1: "佐藤次郎"
2: "鈴木太郎"
3: "北島三郎"
4: "佐藤次郎"

ちなみに、mapが分からない!!という方は ↓↓ の記事で紹介しています。
ES6から使えるmap / filter / reduceの使い方と活用術

合わせて読むと理解が深まるのと、ウェブアプリを作る時は必須レベルの知識です。
なので、今のうちに読んでおいた方がいいですね!
※この記事では必須じゃないのでスルーしてもOKです。

今度は、生成した配列内の重複している値を取り除きます
「鈴木太郎」と「佐藤次郎」が複数ありますね。
これが、それぞれ1つになれば、目標達成です!

Set オブジェクトを使って重複している値を取り除いてあげます。

// Set オブジェクトで重複している名前を削除
const name_list = new Set(map_arr);

前半戦で学んだ通り、Set オブジェクトの宣言時(インスタンスの生成時)に配列を引数に指定してます。
そうすると、重複した値が勝手に取り除かれます!

0: "鈴木太郎"
1: "佐藤次郎"
2: "北島三郎"

抽選機能をカンタンに実装

今度は抽選機能を実装していきます!
抽選機能の仕様は、以下のようになります。

  • ランダムで当選者を5名決める
  • 当選回数は1人1回まで

処理の流れは、こんな感じになります。

  1. 乱数を生成する
  2. 乱数を Set オブジェクトに追加する
  3. 1,2を Set オブジェクトの値が5つになるまで繰り返す

そして、完成系

// 応募者一覧
const data = [
  { id: 1, name: "鈴木一郎" },
  { id: 2, name: "ラーメン二郎" },
  { id: 3, name: "北島三郎" },
  { id: 4, name: "伊東四朗" },
  { id: 5, name: "納谷五郎" },
  { id: 6, name: "納谷六朗" },
  { id: 7, name: "深沢七郎" },
  { id: 8, name: "東八郎" },
  { id: 9, name: "勘九郎" },
  { id: 10, name: "市川團十郎" },
];

const rand_set = new Set();

// 当選者のIDを選出
while(rand_set.size < 5) {
  const rand = 1 + Math.floor(Math.random() * 10); // 1 ~ 9の乱数
  rand_set.add(rand)
}

//  rand_set をもとに data からユーザー情報をフィルタリング
const winner_list = data.filter((user) => {
  if(rand_set.has(user.id)) {
    return user;
  }
});

console.log(winner_list);

解説しますね!

while(rand_set.size < 5) {
  const rand = 1 + Math.floor(Math.random() * 10); // 1 ~ 9の乱数
  rand_set.add(rand)
}

ここでは、当選者のIDを選出しています。

まずは、「0 ~ 9」までのランダムな整数を生成しています。
ここで当選者を決めてる感じですね!

ただ、これだけだと数値が重複してしまう場合もあるので set オブジェクトを使って重複されないようにしています。
重複しないランダムな整数が、rand_setに追加されていきます。

最後に、rand_setの値の個数が5つになるまで while 文で回していきます。

const winner_list = data.filter((user) =&gt; {
  if(rand_set.has(user.id)) {
    return user;
  }
});

今度は、当選者一覧の配列を作ります。
変数dataから条件に合うものを.filter()を使ってフィルタリングしています。

その条件が「ユーザーIDが当選者IDの中に入っている時」になります。

if(rand_set.has(user.id))

filter については、↓↓ の記事で解説しています。
使い方が分からない!!という方は参考にしてみてください。
ES6から使えるmap / filter / reduceの使い方と活用術

filter によって生成された配列にランダムで選ばれたユーザー情報が格納されているはずです!




はいと!いかがだったでしょうか?
今回はES6から使える Set オブジェクトについて紹介しました!

通常の配列で、重複しない配列を作成するには for 文を大量に回す必要があります。
Set オブジェクトを知っているといないとではコードの美しさが段違いです!

ぜひともマスターしておきたいですね!!

他にも Set と同様に扱える Map もあります。
これは後日、紹介しますね~

こんな感じでJavascriptには、たくさんの記述法があります!
たくさんの記述法をネットからピックアップして探し出すのは大変ですよね・・・。

実際、ネットを使えばほとんどの記述方法はゲット出来ると思います。
ただ、非常に効率が悪い・・・。

ネットは情報が多すぎて大混乱!!
そもそも、知らない単語は検索できない!!

なので、ネットと書籍と合わせて勉強していくのが、スキルアップの近道です!

【Javascriptコードレシピ集】なんかは業務レベルで使えるテクニックが網羅されているのでオススメです!

JSをある程度知っている・もっと学習したい方向け
JavaScript コードレシピ集

JSを使って何か実装経験がある方向けの書籍になります。
小技やcanvas・json・fetch・class構文などJSで出来ることが網羅的に紹介されています。
これ1冊あれば実務でもかなり重宝します。