吉本集の個人ブログ
Web制作の技術について書いています。たまに日記も書きます。

【JS入門】配列について Vol.4(配列の要素の並び順をシャッフルする、分割代入)

2018年2月20日 / category : javascript

ArrayオブジェクトのメソッドindexOfとlastIndexOfを解説し、配列の要素をシャッフルするサンプルコードを解説します。このサンプルでは、分割代入という構文を使います。
この構文についても解説します。

メソッドindexOf

array.indexOf(value, form):引数valueと同じ要素を探し、見つかった最初のインデックスを返す
引数 value : 検索をかける要素
引数 form(number) : 検索を始めるインデックス。初期値は0(配列全体)
戻り値(return) : 見つかった最初のインデックス
構文

let index = ['あ','い','う','え','お'].indexOf('う');

sample.js
const data = ['あ','い','う','え','お'];
console.log( data.indexOf('い') ); // 1

上のコードでは、配列dataに対し「い」の文字列がどのインデックスにあるか検索をかけています。インデックス1の要素が「い」ですので、インデックス1を返しています。

sample.js
const data = ['あ','い','う','え','お','い'];
console.log( data.indexOf('い') ); // 1

配列dataの最後に「い」を追加しましたが、結果は変わりません。メソッドindexOfは見つかった要素の中で最初のインデックスを返すためです。

sample.js
const data = ['あ','い','う','え','お','い'];
console.log( data.indexOf('い',2) ); // 5

メソッドindexOfの第2引数に2を設定しました。これで検索対象がインデックス2以降になりました。結果、5が返ってきました。インデックス1の要素が対象外になったためです。
続いて、メソッドlastIndexOfを解説します。

メソッドlastIndexOf

array.lastIndexOf(value, form):引数valueと同じ要素を探し、見つかった最後のインデックスを返す
引数 value : 検索をかける要素
引数 form(number) : 検索を始めるインデックス。初期値は0(配列全体)
戻り値(return) : 見つかった最後のインデックス
構文

let index = ['あ','い','う','え','お'].lastIndexOf('う');

sample.js
const data = ['あ','い','う','え','お','い'];
console.log( data.lastIndexOf('い') ); // 5

メソッドindexOfは、見つかった要素の中で最初のインデックスを返しますが、メソッドlastIndexOfは最後のインデックスを返します。上のコードでは、インデックス1とインデックス5が検索対象になりますが、最後のインデックスを返すため、5が返ってきます。
以上が、Arrayオブジェクトで定義しているメソッドの解説です。

配列の要素の並び順をシャッフルする

次のコードでは、配列の要素をランダムに並び替えています。

sample.js
const arr = [0,1,2,3,4,5,6,7,8,9];
for(let i=0; i<arr.length; i++){
	let ran = Math.floor(Math.random()*(i+1));
	[arr[i], arr[ran]] = [arr[ran], arr[i]];
};
console.log(arr); // (10) [8, 9, 5, 7, 3, 1, 0, 4, 6, 2]

何度かリロードしてコンソールの配列結果を見るとランダムにシャッフルされていることがわかります。
コードはとてもシンプルですが、for文の中で見慣れない1行があります。

[arr[i], arr[ran]] = [arr[ran], arr[i]];

この構文を分割代入と言います。
この分割代入には、配列の分割代入オブジェクトの分割代入の2種類があります。

配列の分割代入

構文

let [a, b] = [10, 20];

sample.js
let [a, b] = [10, 20];
console.log(a); // 10
console.log(b); // 20

変数aに10の値、変数bに20の値が代入されていることが確認できます。

sample.js
let a;
let b;
[a, b] = [10, 20];
console.log(a); // 10
console.log(b); // 20

上のように、宣言後に構文を書くことも可能です。

sample.js
let a;
let b;
[a=10, b=20];
console.log(a); // 10
console.log(b); // 20

上のように、初期値を設定することも可能です。

sample.js
let [a, , b] = [10,20,30];
console.log(a); // 10
console.log(b); // 30

上のような書き方も可能です。この場合、代入する20の値が無視されます。
分割代入は、次のような書き方と同じ処理になりますが、異なる処理になる場合もあります。

■それぞれ変数を宣言して、値を代入する

let a = 10;
let b = 20;

■分割代入

let [a, b] = [10, 20];

上の2つの書き方は同じ処理になります。次のコードを見てみます。

sample.js
let a = 10;
let b = 20;
[a, b] = [b, a];
console.log(a); // 20
console.log(b); // 10

上のコードは、分割代入を使用した変数の入れ替えです。先ほどの配列の要素をランダムに並び替えるコードでも同じ構文が出てきました。

[arr[i], arr[ran]] = [arr[ran], arr[i]];

上のコードでは、変数aに10、変数bに20の値が最初に代入されています。分割代入を使用し、変数の値を入れ替えた結果、変数aに20、変数bに10が再代入されました。
これをそれぞれ変数を宣言して値を入れ替えてみます。

sample.js
let a = 10;
let b = 20;
a = b;
b = a;
console.log(a); // 20
console.log(b); // 20

変数a,bともに20の値が代入されました。これは不思議なことではなく順に処理を行えば、この結果になることがわかります。
これがそれぞれ変数を宣言して値を代入するコードと、分割代入の書き方での違いになります。

オブジェクトの分割代入

構文

let {a, b} = {a:'文字列', b:100};

sample.js
let obj = {name:'吉本', age:37};
let {name, age} = obj;
console.log(name); // 吉本
console.log(age); // 37

上の書き方では、オブジェクトのプロパティ名と代入する変数名が同じでなければならない点に注意してください。もし異なる変数名にしたい場合は次のようなコードになります。

sample.js
let obj = {name:'吉本', age:37};
let {name:a, age:b} = obj;
console.log(a); // 吉本
console.log(b); // 37

上のコードのように、代入するオブジェクトのプロパティに値を指定することで値が変数名になります。

sample.js
let key = 'name';
let {[key]:a} = {name:'吉本'};
console.log(a); // 吉本

上のコードのようにプロパティ名(キー)を別の変数に定義することも可能です。
以上が、分割代入についての解説になります。それでは話を戻し、配列の要素の並び順をシャッフルするコードを改めてみてみます。

sample.js
const arr = [0,1,2,3,4,5,6,7,8,9];
for(let i=0; i<arr.length; i++){
	let ran = Math.floor(Math.random()*(i+1));
	[arr[i], arr[ran]] = [arr[ran], arr[i]];
};
console.log(arr); // (10) [8, 9, 5, 7, 3, 1, 0, 4, 6, 2]

for文の中で分割代入が使われていることがわかります。この使い方は、先ほどの解説に出てきた変数の入れ替えです。変数ranは配列の長さに対するランダム値になるので、上のコードの場合は、0〜9のいずれかになります。このランダム値が配列arrのインデックスとなり、ランダムに要素を取得しているのがarr[ran]の部分になります。このランダムな要素とfor文で順に対象となるarr[i]の要素を入れ替えていることになります。このfor文では、ランダムに配列の要素を入れ替えているという処理を行っていることがわかります。