【STEP.22】
配列(Array)の使い方をマスターしよう!

Contents

配列とは

数値型/文字列型/真偽型が、単一の値を格納するための型であるのに対して、配列とは複数の値をまとめて管理するための型です。

複数の関連した情報を1つの変数でまとめて管理したい場合に利用します。

配列を作成する

配列は、Arrayコンストラクター、リテラル表現のいずれかで作成できます。

以下のコードは、いずれも意味的に等価です。

// Arrayコンストラクター
let data1 = new Array('JavaScript','CoffeeScript','TypeScript');

// リテラル表現
let data2 = ['JavaScript','CoffeeScript','TypeScript'];

ただし、原則として、Arrayコンストラクターは利用すべきではありません。

リテラル表現のほうがシンプルに表現できるという理由もありますが、それ以上にバグの混入を防ぐという意味があります。

以下のコードを見てみましょう。

let data = new Array(5);

一見すると、「5という要素も持った配列」を定義しているようにも見えます。

しかし、Arrayコンストラクターは引数として単一の数値を受け取った場合、それを配列サイズと見なします。

上の例であれば、サイズ5の配列を生成します。

その性質上、以下のようなコードはエラーとなります。

let data = new Array(-5);

サイズ-5の配列を作成することはできないからです。(-5という要素を持った配列を作るわけではありません。)

このように、Arrayコンストラクターは意味的にあいまいになりやすいことから、利用すべきではありません。

空の配列を作成する

空の配列は、以下のように空のブラケットで表現できます。

let data = [];

入れ子の配列を作成する

配列の要素として配列を指定することで、入れ子の配列を作成することもできます。

複雑な配列では、以下の例のように、要素単位に改行を入れることで、構造を把握しやすくなります。

let data = [
   'C#',
   'Java',
   ['MySQL','PostgreSQL','SQLLite'],
];

上の例のように、末尾の要素はカンマで終えてもかまいません。

特に改行区切りで要素を列記しているような状況では、後から要素を追加する場合もカンマの追加漏れを防げます。

配列を参照する

作成した配列は、ブラケット構文で参照できます。

let data = [
   'C#',
   'Java',
   ['MySQL','PostgreSQL','SQLLite'],
];
console.log(data[1]);
// 結果:Java
console.log(data[2][2]);
// 結果:SQLLite

ブラケット([...])には、取得したい配列のインデックス番号(添え字)を指定します。

先頭の要素は(1ではなく)0なので注意してください。

入れ子の配列を参照する場合は、ブラケットも複数列記します。

Arrayオブジェクト

Arrayオブジェクトとは

Arrayオブジェクトは、配列型の値を扱うためのオブジェクトで、配列に対して要素の追加・削除、結合、並び替えなどを行うための機能を提供します。

Arrayオブジェクトで利用できる主なメンバー

Arrayオブジェクトで利用できる主なメンバーは、以下の通りです。

【Arrayオブジェクトで利用できる主なメンバー(*は破壊的メソッド)】
分類メンバー概要
基本length配列のサイズを取得
isArray(obj)指定したオブジェクトが配列であるか(静的メソッド)
toString()「要素,要素,…」の形式で文字列に変換
toLocaleString()配列を文字列に変換(区切り文字はロケールによって変化)
indexOf(search [,from])指定した要素searchに合致した最初の要素のキーを取得(引数fromは検索開始位置)
lastIndexOf(search [,from])指定した要素searchに合致した最後の要素のキーを取得(引数fromは検索開始位置)
keys()
ES2015
すべてのキーを取得
values()
ES2015
すべての値を取得
entries()
ES2015
すべてのキー/値を取得
includes(search [,from])
ES2016
指定された要素searchが配列に含まれているか
(引数fromは検索開始位置)
追加/削除*pop()配列末尾の要素を取得し、削除
*push(data)配列末尾に要素を追加
*shift()配列先頭の要素を取得し、削除
*unshift(data1 [,data2,…])配列先頭の指定要素を追加
加工concat(ary)指定配列aryを現在の配列に連結
join([separator])配列内の要素を区切り文字separatorで連結
slice(begin [,end])begin~end-1番目の要素の抜き出し
*splice(index, many [,elements,…])配列のindex番目からmany個分だけ要素を抜き出し、[,elements,…]で置き換え
from(data [,func [,that]])
ES2015
配列ライクなオブジェクト、列挙可能なオブジェクトを配列に変換(静的メソッド)
of(e1,…)
ES2015
可変長引数を配列に変換(静的メソッド)
*copyWithin(target, start [,end])
ES2015
現在の配列から引数start~end-1番目の要素を抜き出し、引数targetの位置に挿入(要素数は元と変わらない)
*fill(value [,start [,end]])
ES2015
配列内のstart~end-1番目の要素をvalueで置き換え
flat([depth])
ES2019
配列を指定の深さdepthでフラット化
並び替え*reverse()逆順に並び替え(反転)
*sort([fnc])要素を昇順に並び替え
ルバックforEach(fnc [,that])配列内の要素を関数fncで順に処理
map(fnc [,that])配列内の要素を関数fncで順に加工
every(fnc [,that])すべての配列内の要素が条件fncに合致するか
some(fnc [,that])いずれかの配列内の要素が条件fncに合致するか
filter(fnc [,that])条件fncに合致した要素で配列を生成
reduce(fnc [,init])隣同士の2つの要素を左から右へ関数fncで処理して単一の値にする(引数initは初期値)
reduceRight(fnc [,init])隣同士の2つの要素を右から左へ関数fncで処理して単一の値にする(引数initは初期値)
find(fnc [,that])
ES2015
関数fncが初めてtrueを返した要素を取得
findIndex(fnc [,that])
ES2015
関数fncが初めてtrueを返した要素のインデックス値を取得
flatMap(fnc [,that])
ES2019
配列をコールバック関数fncで処理した後にフラット化
MEMO
ー破壊的メソッドー
破壊的メソッドとは、その実行によってオブジェクト(ここでは配列)そのものに変更を及ぼすメソッドのことです。

たとえばreverse/sortなどのメソッドは、戻り値としても並び替え後の配列を返しますが、
元の配列もソートされているので、注意が必要です。

arrayオブジェクトのメンバー

配列のサイズを取得する【lengthプロパティ】

lengthプロパティを利用します。

たとえば以下は、配列の先頭から末尾まで、順に値を取得する例です。

ここでは、配列の末尾を知るために、lengthプロパティを利用しています。

let data = ['ぱんだ','うさぎ','こあら'];
	
for (let i = 0; i < data.length; i++) {
  console.log(data[i]);
}
ぱんだ
うさぎ
こあら

ただし、ES2015以降の環境で配列を列挙するならば、for...of命令を利用するのがシンプルです。

let data = ['ぱんだ','うさぎ','こあら'];

for (let value of data) {
  console.log(value);
}

可能であるならば、こちらを優先して利用します。

lengthプロパティの値を退避させる

ただし、先ほどのソースコードの例では、ループの都度、lengthプロパティにアクセスしているので、ブラウザーの種類/バージョンによっては速度が低下します。

これを避けるために、以下のように、lengthプロパティをあらかじめ変数に退避させておくこともできます。

let data = ['ぱんだ','うさぎ','こあら'];

for (let i = 0, len = data.length; i < len; i++) {
  console.log(data[i]);
}

速度が低下するとはいっても、配列が極端に大きい状況下に限られるので、通常は無視できるはずですが、このような記法もあります。

配列の内容(要素の位置)を検索する【indexOf/lastIndexOf】

indexOflastIndexOfメソッドを利用します。

indexOf/lastIndexOfメソッド

arr.indexOf(search [,from]);
arr.lastIndexOf(search [,from]);
search    検索する要素
from      検索開始位置

indexOfメソッドは配列の先頭から、lastIndexOfメソッドは後方から検索を開始するという違いがあります。

引数fromは、いずれも先頭からのインデックス値として指定します。

戻り値は、見つかった要素位置(先頭要素は0)で、指定の要素が見つからなかった場合には「-1」を返します。

let data = [100, 50, 20, 100];
	
console.log(data.indexOf(100));
// 結果:0
console.log(data.lastIndexOf(100));
// 結果:3
console.log(data.indexOf(300));
// 結果:-1
console.log(data.indexOf('100'));
// 結果:-1
console.log(data.indexOf(100,1));
// 結果:3
console.log(data.lastIndexOf(20,1));
// 結果:-1

indexOflastIndexOfメソッドは、いずれも内部的には===演算子で要素を比較します。

よって、「console.log(data.indexOf('100'));」のように文字列と数値の比較にはマッチしません。

また、引数fromには、負数を指定してもかまいません。

その場合は、配列の末尾を「-1」として、そこからさかのぼって数えた位置から検索を開始します。

ただし、その場合も検索そのものは、indexOfは前から後ろに、lastIndexOfは後ろから前に、検索します。(検索方向が変化するわけではありません。)

let data = [100, 50, 20, 100];

console.log(data.indexOf(50,-2));
// 結果:-1
console.log(data.indexOf(50,-3));
// 結果:1
console.log(data.lastIndexOf(100,-2));
// 結果:0

要素の登場位置をすべて検出する

indexOflastIndexOfメソッドは、指定された要素が最初に見つかった位置を返します。

もしも合致するすべての要素を見つけたい場合には、以下のようなコードを記述します。

function indexOfAll (array, search) {
		
  // 結果を格納するための配列
  let result = [];
		
  // 検索開始位置(最初は先頭)
  let index = -1;
		
  // 要素が見つからなくなるまで検索を継続
  do {
    // 前に見つかった位置の続きから検索
    index = array.indexOf(search, index + 1);
    result.push(index);	
  } while (index !== -1);
  // 結果配列の末尾を除去(「-1」が必ず入っているはずなので)
  return result.slice(0, result.length - 1);
}
	
let data = ['赤','白','青','赤','赤'];
console.log(indexOfAll(data,'赤'));
//結果:[0,3,4]

indexOfメソッドでの戻り値を保存しておいて、次の検索ではその次の要素から検索を開始しています。

検索結果は、配列resultに格納しています。

配列の内容(要素の有無)を検索する【includes】

includesメソッドを利用します。

includesメソッド

arr.includes(search [,from]);
search    検索する要素
from      検索開始位置

配列内で指定された要素が見つかったかどうかをtruefalseで返します。

let data = ['ぱんだ','うさぎ','こあら','うし'];
	
console.log(data.includes('うさぎ'));
// 結果:true
console.log(data.includes('うさぎ',2));
// 結果:false

引数fromには、負数を指定してもかまいません。

その場合は、配列の末尾を「-1」として、そこからさかのぼって数えた位置から検索を開始します。

その場合も、検索は前方から後方に向かって実施されます。

let data = ['ぱんだ','うさぎ','こあら','うし'];
	
console.log(data.includes('うさぎ',-3));
// 結果:true
console.log(data.includes('うさぎ',-2));
// 結果:false

includesメソッドは、ただ要素が存在するかどうかを判定するだけです。

見つかった要素の位置を知りたいならば、indexOflastIndexOfメソッドを利用してください。

逆に、要素の有無だけを判定したいならば、戻り値をtruefalseで返すincludesメソッドのほうが便利です。

配列の要素を追加/削除する【pop/push/shift/unshift】

Arrayオブジェクトには、配列の先頭/末尾それぞれに追加/削除を行うためのメソッドが用意されています。

要素の削除/追加

popshiftメソッドは要素を削除するだけでなく、取得のための役割を担っている点に注目です。(削除というよりも「取り出す」というイメージです。)

let data = ['パンダ','うさぎ','コアラ'];
data.push('ハムスター');
data.unshift('猫');

console.log(data);
// 結果: ["猫", "パンダ", "うさぎ", "コアラ", "ハムスター"]
console.log(data.pop());
// 結果:ハムスター
console.log(data.shift());
// 結果:猫
console.log(data);
// 結果:["パンダ", "うさぎ", "コアラ"]

上記のメソッドを組み合わせることにより、配列をスタック/キューとして利用することができるようになります。

スタックとキュー

スタックとして利用する例

後入れ先出し(LIFO:Last In First Out)、または先入れ後出し(FILO:First In Last Out)と呼ばれる構造です。

たとえば、アプリでよくあるUndo機能では、履歴に追加した操作を、後に入れたものから順に取り出します。

このような操作はスタックが適しています。

スタックを実装するには、pushpopメソッドを利用します。

let data = [1,2,3];
	
console.log(data);
// 結果:[1,2,3]
console.log(data.push(4));
// 結果:4
console.log(data);
// 結果:[1,2,3,4]
console.log(data.pop());
// 結果:4
console.log(data);
// 結果:[1,2,3]

キューとして利用する例

先入れ先出し(FIFO:First In First Out)と呼ばれる構造です。

最初に入った要素を最初に処理する様子が、窓口でサービスを待つ様子と似ていることから、待ち行列と呼ばれることもあります。

キューを実装するには、pushshiftメソッドを利用します。

let data = [1,2,3];
	
console.log(data);
// 結果:[1,2,3]
console.log(data.push(4));
// 結果:4
console.log(data);
// 結果:[1,2,3,4]
console.log(data.shift());
// 結果:1
console.log(data);
// 結果:[2,3,4]

配列に配列を連結する【concat】

配列に対して、(要素ではなく)配列を連結する場合は、concatメソッドを利用します。

concatメソッド

arr.concat(ary)
ary    連結対象の配列

pushshiftメソッドを利用した場合には、配列が要素として追加されてしまうので注意が必要です。

concatメソッドの引数には、複数の配列を指定することもできます。

let data1 = ['ぱんだ','うさぎ','こあら'];
let data2 = ['たぬき','きつね','さる'];
let data3 = ['うし','うま','とり'];

console.log(data1.concat(data2));
// 結果:["ぱんだ", "うさぎ", "こあら", "たぬき", "きつね", "さる"]

//複数連結も可能です。
console.log(data1.concat(data2,data3));
// 結果:["ぱんだ", "うさぎ", "こあら", "たぬき", "きつね", "さる", "うし", "うま", "とり"]
	
// pushメソッドでは入れ子の配列になってしまいます。
data1.push(data2);
console.log(data1);
// 結果:["ぱんだ", "うさぎ", "こあら", ["たぬき", "きつね", "さる"]]

なお、pushメソッドは現在の配列そのものに変更を及ぼすのに対して、concatメソッドは処理の結果を戻り値として返します。(元の配列には影響を及ぼしません。)

pushのようなメソッドのことを破壊的なメソッドといいます。

配列の要素を結合する【join】

joinメソッドを利用します。

joinメソッド

arr.join([separator])
separator    区切り文字

引数separatorを省略した場合、配列は「,」で連結されます。

let data = ['ぱんだ','うさぎ','こあら'];
	
console.log(data.join(''));
// 結果:ぱんだうさぎこあら

console.log(data.join());
// 結果:ぱんだ,うさぎ,こあら

別解としてtoStringメソッドを利用する方法もあります。

toStringメソッドでは、引数は指定できず、配列は無条件に「,」区切りで連結されます。

window.alertメソッドなど、引数として文字列を受け取るメソッドに「window.alert(data);」のように、配列を渡した場合には、自動的にtoStringメソッドが呼び出されます。

let data = ['ぱんだ','うさぎ','こあら'];
	
window.alert(data.toString());
// 結果:ぱんだ,うさぎ,こあら

window.alert(data);
// 結果:ぱんだ,うさぎ,こあら(内部的にはtoStringメソッドを呼び出し)

配列の一部を抜き出す【slice】

配列から特定の一要素を取得するには、ブラケット構文で「data[0]」のように表します。

これを特定範囲で取得するならば、sliceメソッドを利用します。

sliceメソッド

arr.slice(begin [,end])
begin    開始位置
end      終了位置

sliceメソッドは引数beginend-1の要素を抜き出します。

引数endを省略した場合は、開始位置から配列末尾までを取得します。

let data = ['ぱんだ','うさぎ','こあら','たぬき','きつね'];
	
console.log(data.slice(1));
// 結果:["うさぎ", "こあら", "たぬき", "きつね"]
	
console.log(data.slice(1,3));
// 結果:["うさぎ", "こあら"]

引数endに負数を指定することで、「後方から何番目の要素まで」を表すこともできます。

たとえば以下は引数endが「-1」なので、最後の要素から2番目の要素までを抜き出します。

let data = ['ぱんだ','うさぎ','こあら','たぬき','きつね'];

console.log(data.slice(1,-1));
// 結果:["うさぎ", "こあら", "たぬき"]

配列の内容を置き換える【splice】

spliceメソッドを利用します。

spliceメソッド

arr.splice(index, many [,elements,...])
index    開始位置
many     要素数
elements 置換後の要素

配列のindex番目からmany個分だけ要素を抜き出し、elementsで置き換えます。

置換前の要素と置換後の要素の数は違っていてもかまいません。

spliceメソッドも戻り値は、置換対象となった要素(配列)です。(置き換えた結果ではない点に注意する必要があります。)

let data = ['ぱんだ','うさぎ','こあら','たぬき','きつね'];
	
console.log(data.splice(2, 2, 'さる', 'きじ', 'いぬ'));
// 結果:["こあら", "たぬき"]
console.log(data);
// 結果:["ぱんだ", "うさぎ", "さる", "きじ", "いぬ", "きつね"]
console.log(data.splice(0, 1, 'ねこ', 'ぶた'));
// 結果:["ぱんだ"]
console.log(data);
// 結果:["ねこ", "ぶた", "うさぎ", "さる", "きじ", "いぬ", "きつね"]
console.log(data.splice(-2, 2, 'ねずみ'));
// 結果:["いぬ", "きつね"]
console.log(data);
// 結果:["ねこ", "ぶた", "うさぎ", "さる", "きじ", "ねずみ"]

console.log(data.splice(-2, 2, 'ねずみ'));」のように引数indexに負数を指定した場合には、後方から数えた位置(末尾は-1)を開始位置とします。

挿入/削除操作も可能

引数manyを「0」にした場合、既存の要素は抜き出されず、新規の要素が差し込まれるだけ(=挿入)になりますし、引数elementsを省略した場合には既存要素の抜き出し(=削除)になります。

let data = ['ぱんだ','うさぎ','こあら','たぬき','きつね'];
	
console.log(data.splice(2, 0, 'さる'));
// 結果:[]
console.log(data);
// 結果:["ぱんだ", "うさぎ", "さる", "こあら", "たぬき", "きつね"]
console.log(data.splice(4, 2));
// 結果:["たぬき","きつね"]
console.log(data);
// 結果: ["ぱんだ", "うさぎ", "さる", "こあら"]

配列ライクなオブジェクトを配列に変換する【Array.from】

JavaScriptには、argumentsHTMLCollectionのように、「配列によく似た構造を持つが、配列ではない」オブジェクトがあります。

Array.fromメソッドを利用することで、これらのオブジェクトを配列に変換できます。

Array.fromメソッド

Array.from(data [,func [,that]])
data    配列ライクなオブジェクト
func    値変換に利用する関数
that    thisが表す値

たとえばoptionプロパティの戻り値(HTMLOptionsCollection)はforEachメソッドを持ちませんが、fromメソッドで配列化することで、forEachメソッドの利用が可能になります。

<form>
 <div>
  <label for="os">お使いのOSは?</label>
   <select id="os" multiple size="3">
    <option value="windows">windows</option>
    <option value="mac">Mac OS</option>
    <option value="unix">Unix</option>
   </select>
 </div>
</form>
let getListbox = function (name) {

 let result = [];
 let elems = document.getElementById(name).options;

 Array.from(elems).forEach(function (elems) {
  if (elems.selected) {
   result.push(elems.value);	
  }
 });
 return result;
};

document.getElementById('os').addEventListener('change', function(){
  console.log(getListbox('os'));
},false);

Array.fromメソッド

ES2015より前では・・・

Array.fromは、ES2015で導入されたメソッドです。

ES2015より前の環境では、callメソッドを利用します。

上のコードは、callメソッドを利用することで、以下のように書き替えることができます。

これで「optionsの戻り値をthisとして、Array.forEachメソッドを呼び出しなさい」という意味です。

let getListbox = function (name) {

  let result = [];
  let elems = document.getElementById(name).options;

  Array.prototype.forEach.call(elems,function (elems){
    if (elems.selected) {
      result.push(elems.value);	
    }
  });
  return result;
};

document.getElementById('os').addEventListener('change', function(){
  console.log(getListbox('os'));
},false);

配列を複製する【Array.from】

Array.fromメソッドを利用します。

let data = ['ぱんだ','うさぎ','こあら'];

let copy = Array.from(data);

console.log(data);
// 結果:["ぱんだ", "うさぎ", "こあら"]
console.log(copy);
// 結果:["ぱんだ", "うさぎ", "こあら"]
console.log(data === copy);
// 結果:false

fromメソッドは、本来、配列ライクなオブジェクトを配列に変換するためのオブジェクトですが、配列を渡すことで、配列をもとに新しい配列を生成(=配列をコピー)できます。

確かに===演算子で比較すると、内容は同じでも、オブジェクトとしては別のものであることが確認できます。

代入演算子は不可

以下のように、代入演算子を利用しても、参照がコピーされるだけで、配列そのものは同じものを指すことにしかなりません。

let data = ['ぱんだ','うさぎ','こあら'];

let copy = data;

console.log(data);
// 結果:["ぱんだ", "うさぎ", "こあら"]
console.log(copy);
// 結果:["ぱんだ", "うさぎ", "こあら"]

console.log(data === copy);
// 結果:true

fromメソッドのコピーはシャローコピー

fromメソッドによるコピーは、いわゆるシャローコピー(浅いコピー)です。

let data1 = ['a','b','c'];
let data2 = [{x: 1, y: 2},{x: 3, y: 4},{x: 5, y: 6}];
	
let copy1 = Array.from(data1);
let copy2 = Array.from(data2);
	
data1[0] = 'zzz';
data2[0].x = 999;
	
console.log(data1);
// 結果:["zzz", "b", "c"]
console.log(copy1);
// 結果:["a", "b", "c"]
console.log(data2);
// 結果:[{x: 999, y: 2}, {x: 3, y: 4}, {x: 5, y: 6}]
console.log(copy2);
// 結果:[{x: 999, y: 2}, {x: 3, y: 4}, {x: 5, y: 6}]

配列の要素が基本型である場合には問題ありません。

コピー元の修正がコピー先に影響されることはありません。

しかし、参照型である場合、コピー元の修正はコピー先にも影響してしまします。

オブジェクト配下のメンバーではなく、オブジェクトの参照だけをコピーすることから、シャロー(浅い)コピーと呼ばれます。

シャロ―コピーに対して、入れ子になったオブジェクト(配列)の中身まできちんと複製することをディープコピーといいます。

fromメソッド以外でのコピー

(1)concatメソッド

元々は配列同士を連結するためのメソッドですが、引数を空にすることで、元の配列をそのままコピーしたものを返します。

let copy = data.concat();
(2)sliceメソッド

元々は配列から部分配列を取り出すためのメソッドですが、引数に空にすることで、元の配列をそのままコピーしたものを返します。

let copy = data.slice();
(3)スプレッド演算子

元々は配列を可変長引数にばらす用途で利用するものですが、これをコピー用途で利用することもできます。

let copy = [...data];

配列内の要素を別の位置に移動する【CopyWithin】

copyWithinメソッドを利用します。

copyWithinメソッド

arr.copyWithin(target [,start [,end]])
target    移動先
start     コピー開始位置
end       コピー終了位置

現在の配列から、引数startend-1番目の要素を抜き出し、引数targetの位置に挿入します。

引数endを省略した場合は、引数startから末尾までの要素を抜き出します。

let data1 = ['ド','レ','ミ','ファ','ソ'];
let data2 = ['ド','レ','ミ','ファ','ソ'];
let data3 = ['ド','レ','ミ','ファ','ソ'];
	
console.log(data1.copyWithin(2,1,3));
// 結果:["ド", "レ", "レ", "ミ", "ソ"]
console.log(data2.copyWithin(1,2));
// 結果:["ド", "ミ", "ファ", "ソ", "ソ"]
console.log(data3.copyWithin(2));
// 結果: ["ド", "レ", "ド", "レ", "ミ"]

copyWithinメソッド

配列内の要素を特定の値に設定する【fill】

fillメソッドを利用します。

fillメソッド

arr.fill(value [,start [,end]])
value    設定する値
start    開始位置
end      終了位置

fillメソッドは、既定で配列内の要素をすべて指定された値で置き換えますが、引数を指定することで、置き換えの範囲を選択することも可能です。

いずれも負数を指定した場合には、配列末尾から数えて開始/終了位置を決めます。

let data1 = ['ぱんだ','うさぎ','こあら','うし','うま','とり'];
let data2 = ['ぱんだ','うさぎ','こあら','うし','うま','とり','ねずみ','ねこ','いぬ','さる'];
let data3 = ['ぱんだ','うさぎ','こあら','うし','うま','とり','ねずみ','ねこ','いぬ','さる'];
	
console.log(data1.fill('─'));
// 結果:["─", "─", "─", "─", "─", "─"]
console.log(data2.fill('─',2,6));
// 結果:["ぱんだ", "うさぎ", "─", "─", "─", "─", "ねずみ", "ねこ", "いぬ", "さる"]
console.log(data3.fill('─',-7,-2));
// 結果:["ぱんだ", "うさぎ", "こあら", "─", "─", "─", "─", "─", "いぬ", "さる"]

入れ子の配列をフラット化する【flat】

flatメソッドは、入れ子になった配列をフラットな階層に変換します。

flatメソッド

arr.flat([depth])
depth    フラット化すべき階層
let data1 = [100,[200,300],[400,500]];
let data2 = [100,[200,[300,400],[500]]];

console.log(data1.flat());
// 結果:[ 100, 200, 300, 400, 500 ]

//2段ネストの配列をフラット化(デフォルト)
console.log(data2.flat());
// 結果:[ 100, 200, [300, 400], [500] ]

//2段ネストの配列をフラット化(引数指定)
console.log(data2.flat(2));
// 結果:[ 100, 200, 300, 400, 500 ]

flatメソッドは、デフォルトで1段階のネストをフラット化します。

よって、「console.log(data1.flat());」のコードでは2段以降のネストは残ります。

これを完全にフラット化するならば、「console.log(data2.flat(2));」のように引数としてフラット化すべき階層を指定してください。

配列の要素を並び替える【reverse/sort】

reversesortメソッドを利用します。

並びを逆順にする

並びを逆順にするだけであれば、reverseメソッドを利用します。

let data = ['ぱんだ','うさぎ','こあら'];
	
console.log(data.reverse());
// 結果:["こあら", "うさぎ", "ぱんだ"]

配列をソートする

配列を任意のルールで並び替えるには、sortメソッドを利用します。

sortメソッド

arr.sort(function(e1, e2) {
  ...statements...
})
e1, e2      比較する要素
statements  ソート規則

引数には、以下のようなコールバック関数を指定します。

  • 引数は比較する配列要素(2個)
  • 第1引数が第2引数より大きい場合は正数、小さい場合は負数、等しい場合は0を返す。

引数が省略された場合には、引数の文字列として辞書的にソートされます。

let data = [7, 38, 21];
	
console.log(data.sort());
// 結果:[21, 38, 7](辞書的にソート)

console.log(data.sort(function (m, n) {return m - n}));
// 結果:[7, 21, 38](数値の小さい順にソート)

コールバック関数の中では、引数e1e2を数値として両者の差を取るのが一般的です。(これによって、正負の数が返されます。)

役職を基にオブジェクトをソートする

sortメソッドを利用することで、たとえば役職(部長課長係長主任)順にオブジェクトをソートすることもできます。

ポイントは「return key.indexOf(m.position) - key.indexOf(n.position);」の部分、オブジェクト配列のpositionプロパティをキーに配列key(役職順リスト)を検索し、その登場位置で大小比較します。

このように、どのような値も大小比較できる形に変換できれば、ソートが可能です。

//役職順リスト
let key = ['部長','課長','係長','主任'];

//ソート対象のメンバーリスト
let data = [	
  { name:'北村匠海', position: '課長'},
  { name:'岡田将生', position: '主任'},
  { name:'山﨑賢人', position: '主任'},
  { name:'横浜流星', position: '部長'},
];
// 役職(position)の、配列keyにおける位置の大小で比較
console.log(data.sort( function (m, n) {
  return key.indexOf(m.position) - key.indexOf(n.position);
}));
{ name:"横浜流星", position: "部長"}
{ name:"北村匠海", position: "課長"}
{ name:"岡田将生", position: "主任"}
{ name:"山﨑賢人", position: "主任"}

Arrayオブジェクトのメソッドの多くは、破壊的メソッド(=元のオブジェクトに影響を及ぼす)である点に注意する必要があります。

たとえば、sortreverseメソッドは戻り値としてソート後の配列を返しますが、それのみならず、元の配列も並び替えてしまいます。

例外的に、concatslicejointoStringメソッドは破壊的メソッドではありません。

配列の内容を順に処理する【forEach】

forEachメソッドを使えば、配列の要素をコールバック関数で順に処理できます。

forEachメソッド

arr.forEach(function(value, index, array) {
  ...statements...
}, that)
value       要素値
index       インデックス値
array       元の配列
statements  要素に対する処理
that        thisが表す値

たとえば以下は、配列animalsの内容をログ出力します。

コールバック関数の引数は不要であれば、省略することもできます。(ここでは引数valueのみ渡しています。)

let animals = [
  { name:'フレンチブルドッグ', type:'いぬ'},
  { name:'ヨークシャーテリア', type:'いぬ'},
  { name:'ダックスフンド', type:'いぬ'},
  { name:'スコティッシュフォールド', type:'ねこ'},
  { name:'ポメラニアン', type:'いぬ'},
];
	
animals.forEach(function (value){
  console.log(value.name + ':' + value.type);
});
フレンチブルドッグ:いぬ
ヨークシャーテリア:いぬ
ダックスフンド:いぬ
スコティッシュフォールド:ねこ
ポメラニアン:いぬ

thisの内容を変化させる

forEachメソッドの第2引数には、コールバック関数配下でのthisが参照するオブジェクトを指定できます。

たとえば以下のサンプルでは、オブジェクト配列の内容を整形したものを、いったん配列resultに格納したうえで、ログに出力しています。

let animals = [
  { name:'フレンチブルドッグ', type:'いぬ'},
  { name:'ヨークシャーテリア', type:'いぬ'},
  { name:'ダックスフンド', type:'いぬ'},
  { name:'スコティッシュフォールド', type:'ねこ'},
  { name:'ポメラニアン', type:'いぬ'},
];
	
//整形結果を格納するための配列
let result = [];

//配列の内容を整形し、順に結果配列resultに追加
animals.forEach(function (value) {
  this.push(value.name + ':' + value.type);
},result);
	
console.log(result);
[
  "フレンチブルドッグ:いぬ",
  "ヨークシャーテリア:いぬ",
  "ダックスフンド:いぬ",
  "スコティッシュフォールド:ねこ",
  "ポメラニアン:いぬ"
]

配列の要素を順番に加工する【map】

mapメソッドは、配列の要素をコールバック関数で順に加工し、最終的にできた新しい配列を返します。

mapメソッド

arr.map(function(value, index, array) {
  ...statements...
}, that)
value       要素値
index       インデックス値
array       元の配列
statements  要素に対する処理
that        thisが表す値

コールバック関数の引数はいずれも省略可能です。

戻り値は、加工後の値(要素)を返すようにします。

たとえば以下は、個々の配列要素を2乗した配列を返します。

let data1 = [1,2,3];
let data2 = data1.map(function (value){
  return value * value;
});

console.log(data2);
// 結果:[1,4,9]

配列の要素がすべて与えられた条件に合致するか判定する【every】

everyメソッドを利用します。

everyメソッド

arr.every(function(value, index, array) {
  ...statements...
}, that)
value       要素値
index       インデックス値
array       元の配列
statements  要素のtrue/falseを判定する処理
that        thisが表す値

コールバック関数の引数はいずれも省略可能です。

また、要素を判定した結果をtruefalse値で返すようにします。

コールバック関数がすべての要素についてtrueを返した場合に、最終的にeveryメソッドはtrueを返します。

以下は、配列内のすべての要素(文字列)が8文字未満であるかを判定するコードす。

let animals = [
  'フレンチブルドッグ',
  'ヨークシャーテリア',
  'ダックスフンド',
  'ポメラニアン',
  'コーギー',
];

let judge = animals.every(function (value){
  return (value.length < 8)
});

console.log(judge);	
//結果:false

配列内の要素が1つでもtrueであるかを判定したい場合には、someメソッドを利用します。

配列の要素が1つでも与えられた条件に合致するか判定する【some】

someメソッドを利用します。

someメソッド

arr.some(function(value, index, array) {
  ...statements...
}, that)
value       要素値
index       インデックス値
array       元の配列
statements  要素のtrue/falseを判定する処理
that        thisが表す値

コールバック関数の引数はいずれも省略可能です。

また、要素を判定した結果をtruefalse値で返すようにします。

コールバック関数が1つ以上の要素についてtrueを返した場合に、someメソッドもtrueを返します。

以下は、配列内に1つでも8文字未満の要素(文字列)があるかどうかを判定するソースコードです。

let animals = [
  'フレンチブルドッグ',
  'ヨークシャーテリア',
  'ダックスフンド',
  'ポメラニアン',
  'コーギー',
];

let judge = animals.some(function (value){
  return (value.length < 8)
});

console.log(judge);	
//結果:true

配列内の要素がすべてtrueであることを確認したい場合には、everyメソッドを利用します。

配列の内容を特定の条件で絞り込む【filter】

filterメソッドを利用することで、配列の内容をコールバック関数で判定し、その中でtrueと判定された要素だけを取得できます。

filterメソッド

arr.filter(function(value, index, array) {
  ...statements...
}, that)
value       要素値
index       インデックス値
array       元の配列
statements  要素のtrue/falseを判定する処理
that        thisが表す値

コールバック関数の引数はいずれも省略可能です。

戻り値は、結果配列にその要素を残したい場合にはtrue、除去する場合にはfalseを返すようにします。

たとえば以下は、文字列長が8文字未満の要素だけを残すコードです。

let animals = [
  'フレンチブルドッグ',
  'ヨークシャーテリア',
  'ダックスフンド',
  'ポメラニアン',
  'コーギー',
];

let short = animals.filter(function (value){
  return (value.length < 8)
});

console.log(short);	
//結果:["ダックスフンド", "ポメラニアン", "コーギー"]

配列内の要素を順に処理して単一の結果にまとめる【reduce/reduceRight】

reduceメソッドを利用します。

reduceメソッド

arr.reduce(function(result, value, index, array) {
  ...statements...
}, init)
result      結果値
value       要素値
index       インデックス値
array       元の配列
statements  要素を演算する処理
init        初期値

コールバック関数の引数はいずれも省略可能です。

引数resultには、直前のコールバック関数の結果が渡されます。

コールバック関数では、このresultvalueを順に演算し、最終的な結果を得るというわけです。

引数initは、最初にresultに渡す値を表します。

省略された場合には、配列の先頭要素が渡されます。

以下は、配列の内容を順に積算し、その総積を求めるソースコードです。

let data = [2,4,6,8];
console.log(data.reduce(function(result, value){
  return result * value;
}));
// 結果:384

左方向に演算する

reduceメソッドは、配列の要素を左右に演算していきますが、reduceRightメソッドを利用することで、右左方向に演算することもできます。

たとえば以下は、二次元配列をreducereduceRightメソッドを使って、それぞれ一次元配列に変換する例です。

両者の違いを確認します。

let data = [
  ['ぱんだ',2],['うさぎ',5],['こあら',1]	
];
	
console.log(data.reduce(function (result, value) {
  return result.concat(value);
}));
// 結果:["ぱんだ", 2, "うさぎ", 5, "こあら", 1]
	
console.log(data.reduceRight(function(result, value) {
  return result.concat(value);
}));
// 結果:["こあら", 1, "うさぎ", 5, "ぱんだ", 2]

任意の条件で配列内を検索する【find/findIndex】

findfindIndexメソッドを利用します。

条件に合致した要素を取得する

findメソッドを利用することで、配列の内容をコールバック関数で判定し、最初に合致した(=trueを返した)要素を取得することができます。

findメソッド

arr.find(function(value, index, array) {
  ...statements...
}, that)
value       要素値
index       インデックス値
array       元の配列
statements  要素のtrue/falseを判定する処理
that        thisが表す値

コールバック関数の引数はいずれも省略可能です。

また、要素を判定した結果をtruefalseで返すようにします。

以下は、書籍情報の配列から価格が2,000円未満のものを取り出す例です。

let books = [
  {
    title:'お絵描きチュートリアル',
    price:2800,
  },
  {
    title:'鬼滅の刃',
    price:980,
  },
  {
    title:'世界標準の経営理論',
    price:3800,
  },
];
console.log(books.find(function (value){
  return (value.price < 2000);
}));
// 結果:{title: "鬼滅の刃", price: 980}

条件に合致した要素のインデックス値を取得する

findメソッドは条件に合致した要素そのものを返しますが、要素のインデックス値を知りたい場合には、findIndexメソッドを利用します。

先ほどの例を以下のように書き替えて、結果の変化を確認します。

let books = [
  {
    title:'お絵描きチュートリアル',
    price:2800,
  },
  {
    title:'鬼滅の刃',
    price:980,
  },
  {
    title:'世界標準の経営理論',
    price:3800,
  },
];
console.log(books.findIndex(function (value){
  return (value.price < 2000);
}));
// 結果:1

配列の要素を加工した後、フラット化する【flatMap】

flatMapメソッドは、flatメソッドの特殊型で、配列の要素をコールバック関数で加工した後、フラット化します。(いわゆるflat + mapメソッドです。)

flatMapメソッド

arr.flatMap(function(value, index, array) {
  ...statements...
}, that)
value       要素値
index       インデックス値
array       元の配列
statements  要素に対する処理 
that        thisが表す値

たとえば以下は文字列配列の各要素をカンマ区切りした結果を、最終的に1階層の配列にまとめる例です。

let data = ['あいう,かきく','さしす,たちつ,なにぬ','はひふ'];

console.log(data.flatMap(function(value){
  return value.split(',');
}));
// 結果:[ "あいう", "かきく", "さしす", "たちつ", "なにぬ", "はひふ" ]

ソースコードの太字部分(flatMap)をmapに変えた場合には、結果も以下のように変化します。

[["あいう", "かきく"], ["さしす", "たちつ", "なにぬ"], ["はひふ"]]

flatメソッドと異なり、フラット化すべき階層は1階層までです。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です