ダメな方向に行ってます。
リスト操作の関数はそれぞれのやりたいことに責任を持つものです。
JavaScriptのArray.prototypeからめぼしいものを抜き出すとこんな感じ
- map(数学用語): 配列の各要素を加工したい
- filter: 特定用途の要素のものだけを濾し器で取り出したい
- find: 一つだけ抜き出したい
- forEach(each): 「それぞれ(直訳)」を処理する
- reduce(数学用語): 配列を減らして整理する、畳み込み
まぁ英語でフィルタリングしまーすと言いながら、他の配列にpushしてるので
このコードを読んだ人が貴方を「こいつ大嘘吐きのペテン野郎だな」と評価するでしょう。
処理するならforEachを使うべきです。
しかし、重複してるコピペコードをよく見てください。
変更箇所は"102", "201", "202", "303", "401"
の部分だけですよね?
ならば最も適切なのは["102", "201", "202", "303", "401"]
というルームナンバーリストという配列からmapでキー情報を取り出す事になります。
これでコピペコード郡が一掃されます。
それではいきましょう。
js
1const keys = [
2 {"keyno":"A1","room1":"102","room2":"103"},
3 {"keyno":"B2","room1":"201","room2":"202"},
4 {"keyno":"C3","room1":"301","room2":"302","room3":"303"},
5 {"keyno":"D4","room1":"401"},
6];
7
8// このように欲しい鍵情報の配列を準備したが
9// 直接["102", "201", "202", "303", "401"].map(fn)とやっても良い
10const rooms = ["102", "201", "202", "303", "401"];
11const result = rooms
12 .map(room =>
13 keys.filter(x =>
14 Object.keys(x).some(key => /^room/.test(key) && x[key] === room)
15 ).map(x => ({
16 keyno: x.keyno,
17 room: Object.keys(x).find(key => /^room/.test(key) && x[key] === room),
18 room_no: room,
19 }))
20 ).reduce((arr, it) => [...arr, ...it]);
21
22// 結果表示
23console.log(JSON.stringify(result, null, 2));
24// [
25// {"keyno": "A1", "room": "room1", "room_no": "102"},
26// {"keyno": "B2", "room": "room1", "room_no": "201"},
27// {"keyno": "B2", "room": "room2", "room_no": "202"},
28// {"keyno": "C3", "room": "room3", "room_no": "303"},
29// {"keyno": "D4", "room": "room1", "room_no": "401"}
30// ]
reduce((arr, it) => [...arr, ...it])
はfilterがベースになっているので、配列+配列となり、二次元配列になってしまったので潰す目的でこれにしました。
なのでこれは、最初の段階のリファクタリングでしかありません。
続いて本当にfilterが妥当なものなのかを考える必要があります。
before、afterのデータとコードを見る限りfilterである意味が微塵もありません。
一つの鍵で複数の部屋を開けられる(マスターキー?)という時点で仰天ですが、
その割には大した数のドアは開けられませんし、掃除してくれる方に対するセキュリティなのかな?
まぁいいや、清掃担当用のマスターキーと仮定しましょう。
もし一つの部屋が複数のマスターキーで開けられて、
全ての鍵を列挙しなければならないのであれば別ですが、
一つの部屋が一つのマスターでしか開けられない前提ならばfilterは混乱の元でしかないのでfindにしてしまいましょう。
js
1const keys = [
2 {"keyno":"A1","room1":"102","room2":"103"},
3 {"keyno":"B2","room1":"201","room2":"202"},
4 {"keyno":"C3","room1":"301","room2":"302","room3":"303"},
5 {"keyno":"D4","room1":"401"},
6];
7const rooms = ["102", "201", "202", "303", "401"];
8const result = rooms.map(room => {
9 validKey = keys.find(x =>
10 Object.keys(x).some(key => /^room/.test(key) && x[key] === room)
11 )
12 if (validKey) {
13 return {
14 keyno: validKey.keyno,
15 room: Object.keys(validKey).find(key => /^room/.test(key) && validKey[key] === room),
16 room_no: room,
17 }
18 }
19});
20
21console.log(JSON.stringify(result, null, 2));
結果
[
{
"keyno": "A1",
"room": "room1",
"room_no": "102"
},
{
"keyno": "B2",
"room": "room1",
"room_no": "201"
},
{
"keyno": "B2",
"room": "room2",
"room_no": "202"
},
{
"keyno": "C3",
"room": "room3",
"room_no": "303"
},
{
"keyno": "D4",
"room": "room1",
"room_no": "401"
}
]
前回の質問でmaisumakunさんの短い回答があり、あれも素敵な回答ですが、
ワンライナーでゴリゴリと一致するroom名を探しているので、
あちこちで同じ処理を書く羽目になってしまっています。
コピペはバグの温床で技術的負債です。
対応策は2つ
- 共通の処理を関数化して取り出す
- 序盤で
keys.map()
等を使い、予め使いやすい値に加工しておく
この辺を後の課題として残しておきます。
頑張って下さい。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2020/02/12 07:01