スタートページJavascript配列

配列操作記述の簡素化 Arrayメソッド、アロー関数


私が記述して正しい結果が得られたものだけに限定されています。
[テスト]は、説明と同じ内容を実験したものです。
そのコードは[テストソース]で別ウインドウに表示されます。

主なメソッド一覧

アロー関数表示
配列の追加・削除
  pop       末尾要素の削除
  push   末尾要素の追加
  shift     先頭要素の追加
  unshift   先頭要素の削除
  concat    配列の結合
Array.Peototype系の代表的メソッド
  map      配列の個々の要素を処理する
  forEach  配列の個々の要素を処理する
  filter    条件に一致する要素を検索し新しい配列を作る
  reduce   隣接する要素の加工
  sort     ソート
配列の要素検索
  find      条件を満足する最初の要素の値を戻す
  indexOf   一致する要素の位置
  every     すべての要素が条件をみたすか
  some      条件をみたす要素が一つでもあるか
配列の抽出・加工
  slice     配列の部分抽出
  splice    配列の部分抽出。抽出した部分は元配列から削除
  join     配列の全要素を連結した文字列を返す
  split    区切文字で配列にする
Obj配列の一覧
  keys      Obj配列のkey一覧
  values    Obj配列のvalue一覧
  entries   key/value のペアの一覧表 

アロー関数

アロー関数とは、plus = (a,b) => a+b; のように => を用いた関数式の表示方法です。
アロー関数を用いることにより、プログラムの記述が簡素になります。

通常の表示方法
    function 関数名(引数) {
    処理結果 = 処理;
    return 処理結果;
    }

アロー関数の表示方法(1)
 ここでは、JavaScript に標準装備されている Array,Prototype系のメソッドを多く取り扱っています。
 そのときは、次の形式になります(メソッドとは関数のようなものです)。
  処理結果 = 元配列.メソッド名(引数=> 処理)
・引数がないとき
    元配列,メソッド名();
・引数が1つのとき
    元配列,メソッド名(a => a*a);
・引数が複数のとき
    元配列,メソッド名((a,b) => a+b));
・処理が数行になる({ }で囲む)とき
    元配列,メソッド名((a,b) => { 処理1; 処理2; return 結果 }; // return が必要

アロー関数の表示方法(2)
 一般的には関数変数を次のように定義します。
  変数名 = (引数) => { 処理 };
・引数がないとき
    var 変数名 = () => alert("こんにちは");
・引数が1つのとき
    var 変数名 = a => a*a;
・引数が複数のとき
    var 変数名 = (a,b) => a+b;
・処理が数行になる({ }で囲む)とき
    var 変数名 = a => {
    if (a < 0) a = -a;
        return a;  // return が必要
    };

pop,push, shift,unshift

    pop()      末尾を削除
    push()     末尾に追加
    shift()    先頭を削除
    unshift()  先頭に追加

1次元配列(ベクトル v)対象

元配列 v=[10,20,30,40,50];          //             v.length=5
 v.pop()        末尾を削除    // v=[10,20,30,40];    v.length=4
 v.shift()       先頭を削除    // v=[20,30,40,50];    v.length=4
  要素 = 60;                        //                   ↓
  v.push(要素)    末尾に追加        // v=[10,20,30,40,50,60]  v.length=6
  要素 = 1;                         //    ↓
  v.unshift(要素) 先頭に追加        // v=[1,10,20,30,40,50]  v.length=6

2次元配列(行列 m)対象

元配列 m=[ ["阿部","文学部",20],
           ["井上","工学部",20]
         ];                          // m.length=2
追加行ベクトル = ["宇野","文学部",21];

 m.pop()                末尾を削除     // m=[ [阿部,文学部,20] ]  m.length=1
 m.shift()              先頭を削除     // m=[ [井上,工学部,20] ]  m.length=1
  m.push(行ベクトル)     末尾に追加     //  m=[ [阿部,文学部,20].
                                        //      [井上,工学部,20],
                                        //      [宇野,文学部,21] ]; ←追加 m.length=3 
  m.unshift(行ベクトル)  先頭に追加     //  m=[ [宇野,文学部,21], ←追加
                                        //      [阿部,文学部,20],
                                        //      [井上,工学部,20] ];  m.length=3

concat 配列を結合する、配列のコピー

2次元解列の shift,unshift とほぼ同じ機能です。
元配列 m=[ ["阿部","文学部",20],
           ["井上","工学部",20]
         ];                          // m.length=2
追加行ベクトル = ["宇野","文学部",21];

 m1 = m.concat([v]); ベクトルを末尾に追加     // m1=[ [阿部,文学部,20],
            //   ↑2次元配列にするには [] で囲む   //       [井上,工学部,20],
                                                 //       [宇野,文学部,21] ]; ←追加
 m1 = [v].concat(m);  ベクトルを先頭に追加          //  m1=[ [宇野,文学部,21], ←追加
        ↑2次元配列にするには [] で囲む             //       [阿部,文学部,20],
                                                     //       [井上,工学部,20] ];
   この結果、m は変化しません
★配列のコピー
  var m1 = m;
  このとき、m1 に m の各要素の値がコピーされるのではなく、アドレスが渡されるだけです。
    そのため、m1[0][0] = "宇野"; とすると、m[0][0] も "宇野" になり、
  また、m[0][1] = "理学部"; とすると、m1[0][1] も "理学部" になります。
  これを防ぐには for ループで m1[i][j] = m[i][j]; とすれば、m と m1 は独立します。
concat によるコピーでは、m と m2 は独立します。
  var m2 = [];
    for (var i=0; i<m.length; i++) {
      m2[i] = m[i].concat();
    }

ArrayPrototypeメソッド

ArrayPrototypeメソッドは、基本的には通常の配列処理の記述を簡素に記述できる機能です。

一般形
  新配列 = 元配列.メソッド(function(value,index,array){
    配列全体に関する処理:
        return 新配列の値;
    });
例:元配列 v = [10, 20, 30, 40, 50];
    新配列 v1 = v.map(function(value,index,array){  // value だけを使うのでindex,arrayは省略できる
                    return value*value;
                 ]);
    結果 v1 = [100, 400, 900, 1600, 2500]:
 アロー関数表示
    vi = v.map(value => value**value);

・メソッドには、map. forEach, indexOf など多様なものがあります。f
・引数には次の3つがあります。
  第1引数 value(要素の値)
    第2引数 index(要素のインデックス番号)
    第3引数 array(処理している配列)
 ・value などの名称は予約語ではなく自由ですが、通常はこれらを用います。
 ・第1引数は必須ですが、第2・3引数はそれを用いないときは省略できます。
    上の場合、v1 = v.map(function(value){ return value*value;}); としても同じです。
・この { } の内部では、配列は Map配列(連想配列)になります。
    v1 = [{0.10}. {1,20}, ... {4,50}
  それで、 if (index < 2) ~ のような操作もできます。
 しかし、{ } を出た後は、v1 は通常配列ですので、このような使い方はできません。
・第3引数 array については、ここでは取り扱いません。

map 配列の全体要素を同一処理

●一次元配列の場合
元配列 v = [10, 20, 30, 40, 50];

単純コピー
    var v1 = v.map(function(value,index,array){   // index,array は省略可能
        return value;               // v1 =  [10, 20, 30, 40, 50];
    });
コピー後更新 v[0] = 100; v1[1] = 200;           // 一方の変更は他に影響しない
                                                  //    v  = [100, 20, 30, 40, 50];
                                                  //    v1 = [10, 200, 30, 40, 50];
全要素の同一加工
    var v1 = v.map(function(value){         // index.array は省略可能
        return value*value;            // v1 =  [100, 400, 900, 1600, 2550];
    });                      //    全ての要素に適用
 次の記述もできる
    var v1 = v.map(function(value){
        var s = value * value;
        return s;
    });
 アロー関数による表現  v1 = v.map(value => value*value); //  v1 =  [100, 400, 900, 1600, 2550];
index(発生順)による選択
    var v1 = v.map(function(value,index){
        var s = value;
        if (index < 2) s = value*value;      // v1=[100,400,30,40,50]
        return s;
    });
●二次元配列の場合
配列 m = [ 
          ["阿部", "文学部", 20], 
          ["井上", "工学部", 20], 
          ["宇野", "文学部", 21]
         ];
氏名一覧
 v = m.map(function (学生) {
        return 学生[0]      // 氏名だけを戻す
      });
 v = m.map(学生 => 学生.氏名);
  v = [阿部,井上,宇野]
年齢+1
 m1 = m.map(function (学生) {
          学生[2] += 1;        // 全学生の年齢+1
          return 学生          // 行全体を戻す
      } );
 m1 = m.map(学生 => { 学生[2] += 1; return 学生 } );
   m1[0]=[阿部,文学部,21]
   m1[1]=[井上,工学部,21]
   m1[2]=[宇野,文学部,22]
// (注)「学生」は第1引数(value)で各行の [氏名, 学部, 年齢] が指され、氏名は 学生[0] になる
//      名称は自由で定義不要

●二次元Obj配列の場合
配列 m = [ 
           {氏名:"阿部", 学部:"文学部", 年齢:20}, 
           {氏名:"井上", 学部:"工学部", 年齢:20}, 
           {氏名:"宇野", 学部:"文学部", 年齢:21}
         ];
氏名一覧
 v = m.map(function (学生) {
        return 学生.氏名      // 氏名だけを戻す
      });
 v = m.map(学生 => 学生.氏名);
  v = [阿部,井上,宇野]
年齢+1
 m1 = m.map(function (学生) {
          学生.年齢 += 1;      // 全学生の年齢+1
          return 学生          // 行全体を戻す
      } );
 m1 = m.map(学生 => { 学生.年齢 += 1; return 学生 } );
  m1[0]={阿部,文学部,21}
  m1[1]={井上,工学部,21}
  m1[2]={宇野,文学部,22}

forEach 配列の個々の要素を順番に処理する

格納されている複数の要素を取り出し、取り出した要素に対して順番に全ての要素に処理を行ないます。
forEach()の返り値はありません。すなわち、 v1 = v.v.forEach(...) のような記述はできません。

そのため。forEach() の内部で処理が完結し、外部と遮断されます。
    v = [10, 20, 30, 40, 50];
    v.forEach(function(value){
        経過 += " value=" + (value + 100);  // 各要素に100を加える
        document.getElementById(表示場所).innerHTML = 経過;
    });
を行うと、value=110, value=120, ...,  value=150 となりますが、配列 v は変化しません。

外部との連携をするには、forEach の外部で宣言する必要があります。
  全部の合計
  var sum = 0;
    v.forEach(function(value){
        sum += value;              // sum = 150
    });
    v.forEach(value => sum += value);
 先頭の3個の合計
    var sum = 0;
  var item = 3;
    v.forEach(function(value,index){
        if (index < item) sum += value;  // sum = 60 (10+20+30)
    });
●2次元配列の場合
     m = [ 
          ["阿部", "文学部", 20], 
          ["井上", "工学部", 20], 
          ["宇野", "文学部", 21]
         ];
年齢の合計
    var sum = 0;
    m.forEach(function(学生){
        sum += 学生[2];                 // sum = 61
    });
    m.forEach(学生 => sum += 学生[2]);
文学部の学生数
    var cnt = 0;
    m.forEach(function(学生){
        if (学生[1] == "文学部") cnt++;    // cnt=2
    });
    m.forEach(学生 => {if (学生[1] == "文学部") cnt++;});  // if文がありときは{ }で囲む

filter 条件に一致する要素を検索し、合致した新しい配列を作る

配列 v = [10, 20, 30, 40, 50];
値 value < 25 の要素を選択
    v1 = v.filter(function(value){
       return value <= 25;             // v1 = [10,20]   v は不変
    });
  v1 = v.filter(value => value < 25);
発生順序 index >= 2 の要素を選択
    v1 = v.filter(function(value,index){
       return index >= 2;       // v1 = [30,40,50]
    });
  v1 = v.filter((value,index) => index >= 2)
●2次元配列の場合  m1 = m.filter(学生 => 学生[1] === '文学部')
    m = [ 
          ["阿部", "文学部", 20], 
          ["井上", "工学部", 20], 
          ["宇野", "文学部", 21]
        ];
文学部 だけを選択
    m1 = m.filter(学生 => 学生[1] === '文学部');
    // m1[0]=阿部,文学部,20
    // m1[1]=宇野,文学部,21
●2次元Obj配列の場合
    m = [ 
          {氏名:"阿部", 学部:"文学部", 年齢:20}, 
          {氏名:"井上", 学部:"工学部", 年齢:20}, 
          {氏名:"宇野", 学部:"文学部", 年齢:21}
       ];
学部=文学部 だけを選択
  m1 = m.filter(学生 => 学生.学部 === '文学部');
     // m1 = [
     //        {氏名:"阿部", 学部:"文学部", 年齢:20}, 
     //        {氏名:"宇野", 学部:"文学部", 年齢:21}
     //     ];
     // ここでの「学生」は「各行」の意味。名称は自由だし定義も不要

reduce 隣接する要素の加工

配列  v = [30, 20, 50, 10, 40];
合計の計算
    var s = v.reduce(function(a, b){
        return a + b;     │   ─┐
    });            │    │
   アロー関数 s = v.reduce((a, b) => a + b);
                └ 引き数が複数なので () で囲む
 処理の動き
   reduce(a,b)では、第1引数 a には「蓄積された値」、第2引数 b には「現在の要素」が渡されます。
  a には初期値として配列の先頭の要素 30, b にはその次の要素 20 が渡されます。
   a    b   a+b
     30   20    50
     50   50   100
    100   10   110
    110   40   150 ←戻り値

最大値の計算
    var s = v.reduce(function(a, b){
        return Math.max(a,b);
    });
  アロー関数 s = v.reduce((a, b) => Math.max(a,b));
 処理の動き
   a    b   max
     30   20    30
     30   50    50
     50   10    50
     50   40    50 ←戻り値

sort ソート

私には、内部処理を説明できないのですが、次のコードでソートできます。
配列  v = [30, 20, 50, 10, 40];
昇順ソート → v1 = [10, 20, 30, 40, 50]
  v1 = v.sort(); 
  v1 = v.sort(function(a,b){ return a - b;});
  v1 = v.sort((a, b) => a - b);
降順ソート → v1 = [50, 40, 30, 20, 10]
  v1 = v.sort(function(a,b){ return b - a;});
  v1 = v.sort((a, b) => b - a);
●二次元Obj配列のソート
var m = [ 
          {氏名:"阿部", 学部:"文学部", 年齢:20}, 
          {氏名:"井上", 学部:"工学部", 年齢:19}, 
          {氏名:"宇野", 学部:"文学部", 年齢:21}
       ];
年齢の昇順にソート
   m.sort((a,b) => a.年齢 - b.年齢);
ソート後
   m[0] 氏名 =井上, 学部=工学部, 年齢=19
   m[1] 氏名 =阿部, 学部=文学部, 年齢=20
   m[2] 氏名 =宇野, 学部=文学部, 年齢=21

find 条件を満足する最初の要素の「値」

配列 v = [10, 20, 40, 40, 50]; 

要素 >30 の最初の要素
    var s = v.find(function(value){
	return value > 30;             // s = 40
    });
 アロー関数表示
  s = v.find(value => value > 30);   // s = 40 
要素 <30 の最初の要素
    var s = v.find(function(value){
	return value < 0;             // s = undefined 存在しない
    });

indexOf / lastindexOf  条件を満足する最初の要素の「位置」

indexOf 先頭から探す  indexOf 末尾から探す

配列 v = [10, 20, 40, 40, 50]; 
 要素 40 の最初の位置 i = v.indexOf(40);      // i=2
 要素 40 の最後の位置 i = v.lastIndexOf(40);  // i=3
 要素 25 の最初の位置 i = v.indexOf(40);      // i=-1 存在しないと -1 が戻る
 (二次元配列で適用できれば「阿部がある行番号は?」などができるのですが、うまくいきません)

every すべての要素が条件を満たすか

●1次元配列のとき
  配列 v = [10, 20, 40, 40, 50];
 すべての要素は0より大か?   v.every(value => value > 0);    // i=true
 すべての要素は30より大か? v.every(value => value > 30);   // i=false
●2次元Obj配列の場合
    配列 m = [ 
              {氏名:"阿部", 学部:"文学部", 年齢:20}, 
              {氏名:"井上", 学部:"工学部", 年齢:20}, 
              {氏名:"宇野", 学部:"文学部", 年齢:21}
            ];
 すべての学生が文学部か?      i = m.every(学生 => 学生.学部 === '文学部'); // i=false
 全ての学生は、年齢 >= 20 か? i = m.every(学生 => 学生.年齢 >= 20);        // i=true
 (注)ここでの「学生」は「各行」の意味。名称は自由て事前定義は不要)
    学生.学部 === '文学部' は == でも正しく動くが、厳密には === を用いる

some 条件をみたす要素が一つでもあるか

●1次元配列の場合
  配列 v = [10, 20, 40, 40, 50];
 30より大の要素があるか? i = v.some(value => value > 30);   // i=true
 25の要素はあるか?    i = v.some(value => value === 25); // i=false
●2次元Obj配列の場合
    配列 m = [ 
              {氏名:"阿部", 学部:"文学部", 年齢:20}, 
              {氏名:"井上", 学部:"工学部", 年齢:20}, 
              {氏名:"宇野", 学部:"文学部", 年齢:21}
            ];
 文学部 の学生がいるか?     i = m.some(学生 => 学生.学部 === '文学部'; // i=true
 年齢 < 20 の学生がいるか?  i = m.some(学生 => 学生.年齢 < 20);        // i=false
 (注)ここでの「学生」は「各行」の意味。名称は自由て事前定義は不要)
    学生.学部 === '文学部' は == でも正しく動くが、厳密には === を用いる

slice / splice

slice 配列の部分抽出

一般形;新配列 = 元配列.slice(最初位置, 最後位置-1) // -1 に注意
元配列 v = [10,20,30,40,50];
    v1 = v.slice(1, 3);  // v1=[20, 30]     v[1], v[2] を取り出す。v[3]は取り出さない
                         // v=[10,20,30,40,50]   元配列は変化しない
   v1 = v.slice(2);     // v1=[30,40,50]  第2引数を省略すると元配列の最後までの指定になる
    v1 = v.slice(1, -2); // v1=[20,30]     第2引数を負数にすると元配列の最後からの指定になる
  1次元配列では、抽出後の変更は他に影響を与えない
    v1 = v.slice(1, 3)後に v[1] = 200; v1[1] = 300;  
     v=[10,200,30,40,50]  v1=[20,300]

2次元配列のとき
元配列 m = [[0, 1, 2], [10, 11, 12], [20, 21, 22],[30, 31, 32], [40, 41, 42], [50, 51, 52]];
    m1 = m.slice(1, 3);  // m1=[ [10,11,12], [20,21,22] ]
 2次元配列のときは m,m1 の変更は他に反映される  m[1][0] = 100; m1[1][0] = 200;
    m = [[0, 1, 2], [100, 11, 12], [200, 21, 22],[30, 31, 32], [40, 41, 42], [50, 51, 52]]; 元配列 m = [];
    m1=[ [100,11,12], [200,21,22] ]

splice 配列の部分抽出。抽出した部分は元配列から削除

一般形;新配列 = 元配列.splice(最初位置, 要素数)
配列 v=10,20,30,40,50
    v1 = v.splice(1, 3)      // v1=[20,30,40]   v=[10,50]
  第2引数を省略すると元配列の最後までの指定になる
    v1 = v.splice(2)         // v1=[30,40,50]  v=[10,20]
2次元配列のとき
元配列 m = [[0, 1, 2], [10, 11, 12], [20, 21, 22],[30, 31, 32], [40, 41, 42], [50, 51, 52]];
    m1 = m.splice(1, 3);  // m1=[ [10,11,12], [20,21,22], [30,31,32]]
                          // m =[ [ 0, 1, 2], [40,41,42], [50,51,52]]
   (m と m1 は重複しないので、一方の更新は他に影響sじない)

join 配列の全要素を連結した文字列を返す

一般形;新配列 = 元配列.join(区切り文字)
配列 v = ["A", "B", "C", "D", "E"];
    str = v.join('/')  // str="A/B/C/D/E"
    str = v.join();    // str="A,B,C,D,E"
    str = v.join('')   // str="ABCDE"

split 区切文字で配列にする

一般形;配列 = 文字列.split(区切り文字) 
    str = "A,  B,  C";  v = str.split(',');
       //  v[0]="A"; v[1]="  B"; v[2]="  C"  空白も入れられる
    str ="A B  C";  v = str.split(' ');  //  「半角スペース」で分離
       // v[0]="A"; v[1]="B"; v[2]=""; v[3]="C" 
       //      連続した空白があると、その間に '' があるとして配列に入れられる

str.split(元文字).join(新文字); join と組み合わせて置換する。
    str ="A B  C";
    str1 = str.split(' ').join('*');  // 空白→* 
      // str1="A*B**C"

keys / values / entries   Ojb配列の key / value / そのペアの一覧

1次元Obj配列のとき
 入力
  v = {氏名:"阿部", 学部:"文学部", 年齢:20};

 キー表 = Object.keys(v)  // キー表 = 氏名,学部,年齢
                            //     キー表[0]=氏名
 値表 = Object.values(v)    // 値表 = 阿部,文学部,20
                             //     値表[0]=阿部
  対応表 = Object.entries(v) // 対応表=氏名,阿部,学部,文学部,年齢,20
                             //    対応表[0]=氏名,阿部
                             //    対応表[0][0]=氏名, 対応表[0][1]=阿部
2次元Obj配列のとき
 入力
    var m = [
              {氏名:"阿部", 学部:"文学部", 年齢:20},
              {氏名:"井上", 学部:"工学部", 年齢:20}
            ];
 対象行を指定すれば1次元と同じ
 キー表 = Object.keys(m[0])  // キー表=氏名,学部,年齢
               //    キー表[0]=氏名

 ★応用;obj配列から列名行つき通常配列を作成
    var 配列 = [];            // 配列 = [
    配列[0] = Object.keys(m[0]);     //   [氏名,学部,年齢], ←列名行
    for (var i=0; i<m.length; i++) {   //  [阿部,文学部,20],
        配列[i+1] = Object.values(m[i]); //   [井上,工学部,20],
    }                  // ];