走れメロス?
メロス(後輩)は激怒した。
かの邪智暴虐な王(常駐先のエンジニア)を除かなければならぬと決意した。
後輩はフロントエンジニアなのだが、
どうやら、バックエンド側のエンジニアが、今からコードを改修するのが面倒くさいらしく、
バックエンド側で持っているデータを、わざわざフロント側でゴニョゴニョして、
生成しなければならなくなったそうです。
詳細を聞くと
どうやら
「listAとlistBがあって、ダブっているものがあったら、listAに何か目印を追加してほしい」
というのが、今回の要件でした。
仮にこんな感じのデータがあったと想定してみます。
※「一郎」「三郎」「四郎」をダブらせています。
let listA = [
{id:1, name:"一郎"},
{id:2, name:"二郎"},
{id:3, name:"三郎"},
{id:4, name:"四郎"},
{id:5, name:"五郎"}
];
let listB = [
{id:4, name:"四郎"},
{id:7, name:"七郎"},
{id:9, name:"九郎"},
{id:3, name:"三郎"},
{id:1, name:"一郎"}
];
ループ中のループ
後輩は、ループの入れ子で実装したらしく、ループが無駄にならないように、きちんとbreakしたとのこと。
おそらく、こんな感じでしょうか。
for(let i=0; i<listA.length; i++){
listA[i].flag = false;
for(let j=0; j<listB.length; j++){
if(listA[i].id == listB[j].id){
listA[i].flag = true;
break;
}
}
}
確かに、実装はできています。
でもいろいろと、改良の余地がありそうですね。
mapで書いてみる
さらに詳しく聞いてみると、
「これだとループ中にループがあってイケてないから、mapで書き直して」
と言われたそうです。
もし私が、実装するとしたら、以下のような感じでしょうか。
listA = listA.map(a => ({id:a.id, name:a.name, flag:listB.some(b=>b.id==a.id)}));
リスト表示用の関数
さっそく、改良前と改良後で結果が同じかどうか、JSON形式で画面に出力してみました。
関数の定義は以下の通り。
function Display(list){
let result = JSON.stringify(list, undefined, 4);
result = result.replace(/\n/g, "<br>").replace(/\s/g, " ");
document.write(result);
}
この関数は、連想配列を受け取ってJSON文字列に変換します。
そして、JSON文字列をHTMLで表示するために、改行と半角スペースを置換しています。
それでは
実際に表示させてみます。
listA = listA.map(a => ({id:a.id, name:a.name, flag:listB.some(b=>b.id==a.id)}));
Display(listA);
[
{
"id": 1,
"name": "一郎",
"flag": true
},
{
"id": 2,
"name": "二郎",
"flag": false
},
{
"id": 3,
"name": "三郎",
"flag": true
},
{
"id": 4,
"name": "四郎",
"flag": true
},
{
"id": 5,
"name": "五郎",
"flag": false
}
]
うん!ちゃんとできてますね!
まとめ
mapは便利ですね~。
私はC#の経験が一番長いのですが、Linqとよく似ています。
アロー演算子はゴーズトゥ演算子と同じですし、someはanyと同じですし。
今回は以下の記事を大いに参考にさせていただきました。
JavaScriptでforEach, filter, map, reduceとか
この調子で、実務で使用するJavaScriptでも、無駄なループが減らしながら、
見やすいコードを書いていきたいですね (^_^;