LoginSignup
0
0

More than 3 years have passed since last update.

深さがバラバラの配列からスマートに値を取り出す。reduceで。[JavaScript]

Posted at

導入

こんな配列と取り出したいデータの場所を表す配列があったとします

var arr=[
  [['000', '001', '002'], ['010', '011', '012'], ['020', '021', '022']],
  [['100', '101', '102'], ['110', '111', '112'], ['120', '121', '122']],
  [['200', '201', '202'], ['210', '211', '212'], ['220', '221', '222']]
];
var pos =[0,2,2],
    pos1=[1,0,2],
    pos2=[2,1,0];

多次元配列って呼ばれているやつです
データの場所を投げたら目的のデータが返ってくる関数が欲しいという設定です
この場合なら次の例が一番分かりやすいと思います

const fx=x=>arr[x[0]][x[1]][x[2]];

console.log(fx(pos ));
console.log(fx(pos1));
console.log(fx(pos2));
// >> '022'
// >> '102'
// >> '201'

同じような状況で配列がこんな場合はどうでしょう

arr=[
  [['000', '001'], '01', ['020', '021', ['0220', '0221']]],
  ['10', ['110', '111', '112'], '12'],
  [[['2000', '2001', '2002'], '201', ['2020', '2021']], ['210', '211']]
];
pos =[0,2,2,0];
pos1=[1,0];
pos2=[2,0,2,1];

先程の関数に通してみます

console.log(fx(pos ));
console.log(fx(pos1));
console.log(fx(pos2));

// >> ['0220', '0221']
// >> undefined
// >> ['2020', '2021']

場所によって深さが違うことが原因のようです
そこでこんな関数を作ってみました

const fx_=x=>x.reduce((a,c)=>a[c],arr);

console.log(fx_(pos ));
console.log(fx_(pos1));
console.log(fx_(pos2));

// >> '0220'
// >> '10'
// >> '2021'

便利。

解説

そもそもreduceとは

Array.prototype.reduce() MDN

arr.reduce(callback[, initialValue]);

  • arr : 処理をしたい配列
  • callback : コールバック関数 処理をここに書く 引数は以下の4つ
    • accumulator : 前の処理の戻り値 or 最初の要素 or initialValue
    • currentValue : 現在処理されている配列の要素
    • index : 現在処理している配列のインデックス 必須ではない
    • array : 処理している配列 必須ではない
  • initialValue : 一番最初の処理でaccumulatorとして渡される値 必須ではない

配列全部の要素を使って何か一つの値を出すのに向いてます
よく挙げられる配列の全要素の合計を出す例で動作を見てみます

var tmp=[1,2,3,4,5].reduce((a,c,i)=>{
  console.log(a,c,i);
  return a+c;
});
console.log(tmp);

// >> 1, 2, 1
// >> 3, 3, 2
// >> 6, 4, 3
// >> 10, 5, 4
// >> 15

注目して欲しいのがインデックス番号です
0からではなく1から始まっています
そして最初のaccumulatorに0番目の要素が使われています
initialValueを入れて実行してみます

var tmp=[1,2,3,4,5].reduce((a,c,i)=>{
  console.log(a,c,i);
  return a+c;
},0);// initialValue=0
console.log(tmp);

// >> 0, 1, 0  ←処理が増えてる
// >> 1, 2, 1
// >> 3, 3, 2
// >> 6, 4, 3
// >> 10, 5, 4
// >> 15

0, 1, 0の出力があります
つまりinitialValueがないと
本来initialValueとarr[0]で行われる処理がなくなる
ということです

単純な数の演算ではない使い方をする場合は
恐らくこちらの方が都合が良いことが多いでしょう

冒頭ではこの仕様を使って配列からデータを取り出しています

var arr=[
  [['000', '001'], '01', ['020', '021', ['0220', '0221']]],
  ['10', ['110', '111', '112'], '12'],
  [[['2000', '2001', '2002'], '201', ['2020', '2021']], ['210', '211']]
];
var pos =[0,2,2,0];

const fx_=x=>x.reduce((a,c)=>{
  console.log(a,c);
  return a[c];
},arr);// arrが最初のaccumilatorに渡される

console.log(fx_(pos));

// >> [[["000","001"],"01",["020","021",["0220","0221"]…, 0
// >> [["000","001"],"01",["020","021",["0220","0221"]]], 2
// >> ["020","021",["0220","0221"]], 2
// >> ["0220","0221"], 0
// >> "0220"

配列に一階層ずつ潜っていく様子がわかります

さいごに

そもそもこんな複雑な配列を作るなら連想配列を使うべきだったと思います
反省してます…

最後まで読んでくださりありがとうございます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0