実現したいこと
お店idを格納した配列と、お店の情報が格納された配列があります。
JavaScript
1const shopIds = [1, 2]; 2const shops = [ 3 { id: 1, name: "テラ貴族", isOpen: true}, 4 { id: 2, name: "テラサカバ", isOpen: true}, 5 { id: 3, name: "テラ民", isOpen: true}, 6 { id: 4, name: "テラ木屋", isOpen: true}, 7];
配列shopIdsに格納されたidを持つshopのisOpenフラグをfalseに書き換えるプログラムを書きました。
shopIds.forEach(id => { shops.forEach(shop => { if (shop.id === id) { shop.isOpen = false; } }); });
現在、2重でループさせることでフラグを書き換えていますが、これをmapやfilterなどのメソッドを使ってスマートに書く方法を模索しています。ご教授いただけますと幸いです。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/12/28 02:50
2018/12/28 02:55
2018/12/28 03:02
回答5件
0
ベストアンサー
constで作ったオブジェクトに対して破壊的操作で値をいじるのはあまり良くありません。
という訳で両方のケースで書きます。
今回の質問文には書かれてませんが、
多分このshopIds
は何らかの事情によりWebサイト上で一時的に準備中にしたいという目的で定義された変数だろうと推測されます。
なのでそれ想定で書いてます。
プロパティの値に代入はオブジェクトの破壊的な操作になります。
今回のような破壊的操作を伴う場合、戻り値は不要なのでmapは使わずforEachを使うようにしてください。
mapを使うと未来の貴方や、他のメンバーは「戻り値を使って何かしたいんだ」と勘違いする要因になるので決して使わないでください。
また、こういう2つの配列を使う場合はどちらを起点にするかでコードの長さが変わります。
両方書いてみてしっくり来る方を選びましょう。
shopIdsを先に使うとこんな感じのコードになります。
JavaScript
1shopIds.forEach(id => 2 (shops.find(it => it.id === id) || {}).isOpen = false 3); 4console.log(shops); 5// (4) [{…}, {…}, {…}, {…}] 6// 0: {id: 1, name: "テラ貴族", isOpen: false} 7// 1: {id: 2, name: "テラサカバ", isOpen: false} 8// 2: {id: 3, name: "テラ民", isOpen: true} 9// 3: {id: 4, name: "テラ木屋", isOpen: true}
findの結果で見つからない場合undefinedになり、undefinedのプロパティを操作しようとするとエラーが出ます。
or演算子で空オブジェクトを生成して返すようにすることでプロパティの操作が出来るようにしました。
showIdsが常に存在するIDならば決め打ちでいけるのでもう少しかわいいコードになります
JavaScript
1shopIds.forEach(id => 2 shops.find(it => it.id === id).isOpen = false 3); 4 5// あるか無いか分からない場面だと先にfilter使うんだけど、ちょっと冗長かなぁ? 6shopIds 7 .filter(id => shops.some(it => it.id === id)) 8 .forEach(id => shops.find(it => it.id === id).isOpen = false)
逆にshopsを使えばこのようなコードになるでしょう。
JavaScript
1shops.forEach(it => { 2 if (shopIds.includes(it.id)) it.isOpen = false 3}) 4console.log(shops); 5// (4) [{…}, {…}, {…}, {…}] 6// 0: {id: 1, name: "テラ貴族", isOpen: false} 7// 1: {id: 2, name: "テラサカバ", isOpen: false} 8// 2: {id: 3, name: "テラ民", isOpen: true} 9// 3: {id: 4, name: "テラ木屋", isOpen: true} 10 11// こちらもfilter版、かなりシンプルでスマート! 12shops 13 .filter(it => shopIds.includes(it.id)) 14 .forEach(it => it.isOpen = false)
オブジェクトの破壊的操作を避け、コピーする想定でいくならこんな感じになります。
JavaScriptのプロパティ値に代入する方法は破壊的操作なので使えません。
mapとシャロコピーを併用する方式になります。
shopIdsを主軸にすると変更+変更してないショップ一覧にたどり着くのが困難になりますので、
shops.mapを主軸にするのが適切でしょう。
JavaScript
1const initialisedShops = shops.map(it => ({ 2 ...it, isOpen: shopIds.includes(it.id) ? false : it.isOpen 3})); 4console.log(initialisedShops); 5// (4) [{…}, {…}, {…}, {…}] 6// 0: {id: 1, name: "テラ貴族", isOpen: false} 7// 1: {id: 2, name: "テラサカバ", isOpen: false} 8// 2: {id: 3, name: "テラ民", isOpen: true} 9// 3: {id: 4, name: "テラ木屋", isOpen: true}
投稿2018/12/28 02:38
編集2018/12/28 04:37総合スコア21158
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
こうでしょうか。
js
1shops.map(shop => shopIds.includes(shop.id) ? {...shop, isOpen: false} : shop);
includes
, Object.assign
についてはご自身で確認してください。
投稿2018/12/28 01:46
編集2018/12/28 07:03総合スコア6753
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
jsは参照渡しているのでmapで返す必要はないですね
javascript
1const shopIds = [1, 2]; 2const shops = [ 3 { id: 1, name: "テラ貴族", isOpen: true}, 4 { id: 2, name: "テラサカバ", isOpen: true}, 5 { id: 3, name: "テラ民", isOpen: true}, 6 { id: 4, name: "テラ木屋", isOpen: true}, 7]; 8shops.forEach(function(x){ 9 x.isOpen=!shopIds.some(function(y){return y=== x.id;}); 10}); 11console.log(shops);
もう少し複雑な条件になった場合も想定するとfilterしてからforEachするという考え方もあります
javascript
1shops.filter(function(x){ 2 return shopIds.some(function(y){return y=== x.id;}); 3}).forEach(function(x){ 4 x.isOpen=false; 5});
訂正版
含まれない場合はそのままという処理としました
javascript
1const shopIds = [1,2]; 2const shops = [ 3 { id: 1, name: "テラ貴族", isOpen: null}, 4 { id: 2, name: "テラサカバ", isOpen: true}, 5 { id: 3, name: "テラ民", isOpen: null}, 6 { id: 4, name: "テラ木屋", isOpen: true}, 7]; 8shops.forEach(function(x){ 9 if(shopIds.some(function(y){return y=== x.id;})){ 10 x.isOpen=false; 11 } 12}); 13console.log(shops);
投稿2018/12/28 01:45
編集2018/12/28 03:21総合スコア114839
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/12/28 02:50
2018/12/28 03:22
2018/12/28 04:21
2018/12/28 04:25
0
JavaScript
1const result = shops.map(shop => { 2 shop.isOpen = !shopIds.includes(shop.id); 3 return shop; 4}); 5console.log(result); 6/* 7 * 0: Object { id: 1, name: "テラ貴族", isOpen: false } 8 * 1: Object { id: 2, name: "テラサカバ", isOpen: false } 9 * 2: Object { id: 3, name: "テラ民", isOpen: true } 10 * 3: Object { id: 4, name: "テラ木屋", isOpen: true } 11 */
shopIdsに含まれていない場合にはisOpenを更新しない版
JavaScript
1var result = shops.map(shop => { 2 if (shopIds.includes(shop.id)) shop.isOpen = false; 3 return shop; 4});
投稿2018/12/28 01:28
編集2018/12/28 04:49総合スコア4666
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/12/28 03:00 編集
2018/12/28 04:41
0
こんなんでどうでしょう
javascript
1const shops2 = shops.map(shop => ({ 2 ...shop, isOpen: !shopIds.includes(shop.id) 3}))
投稿2018/12/28 01:36
編集2018/12/28 01:38総合スコア112
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/12/28 02:50
2018/12/28 04:43
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。