🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

Q&A

解決済

1回答

1603閲覧

jQeuryオブジェクト抽出で、子階層の場合の処理について

kuroean

総合スコア12

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

0グッド

0クリップ

投稿2019/09/29 03:55

###実現したいこと
オブジェクトを抽出するとき、親階層と子階層を、同じ関数get_extractObjで抽出したいです。

###対象のオブジェクト
ご覧のように親階層にも子階層にも"post_type":"media"があり、これらをうまく取得する方法を模索しています。

/* * 対象のオブジェクトを取得 ***************************************************/ function getObj(){ var obj = { "obj": { "library": [ {"area":"library","post_type":"media","media_id":"10"}, {"area":"library","post_type":"comment","comment_id":"100"} ], "timeline": [ {"area":"timeline","post_type":"comment","comment_id":"100"}, {"area":"timeline","post_type":"comment","comment_id":"200", "attached": { "media":[ {"area":"timeline","post_type":"media","media_id":"10"} ] } }, {"area":"timeline","post_type":"comment","comment_id":"300", "attached": { "media":[ {"area":"timeline","post_type":"media","media_id":"10"}, {"area":"timeline","post_type":"media","media_id":"20"} ] } } ] } } return obj; }

###試したこと・不安
こちらのコードでいちおう出来てはいるものの、抽出の流れに不安がございます。
https://jsfiddle.net/xw6e8gb7/

関数get_extractObjは、targetObjからtargetIdのオブジェクトを抽出するという機能です。

抽出の対象が親階層の場合は問題ないと思います。

しかし子階層の場合は、まず親オブジェクトの取得を経る次の➀➁➂の流れになっていまして、これが無駄なのではないか?と不安に思いました。

get_extractObj()の引数にparentIdparentTypeという親情報を渡し、
➁そこからparentObjという親オブジェクトを取得し、
➂その中から改めてextractObjという目的のオブジェクトを抽出する。

###質問
親情報を渡したり親オブジェクトの取得を経なくても、extractObjを抽出する方法があるのではないか?と思い、その方が引数が減りますし、処理も早くなりそう(?)なので質問させて頂きました。

どなたかお詳しい方がいらっしゃいましたら、どうぞ宜しくお願い致します。

###jsfiddleのコード
先述したjsfiddleのコードになります。

/* * target_objから、target_idのオブジェクトを抽出 ***************************************************/ function get_extractObj( targetObj, area, targetType, targetId, parentType=null, parentId=null ){ let extractObj; const areaObj = targetObj['obj'][area]; // 親階層について、targetIdのオブジェクトを抽出 if( parentType==null ){ extractObj = areaObj.find( e=>e[targetType+'_id'] && e[targetType+'_id'] === targetId ); } // 子階層について、parentIdのオブジェクトのattachedから、targetIdのオブジェクトを抽出 if( parentType!=null ){ const parentObj = areaObj.find( e=>e[parentType+'_id'] && e[parentType+'_id'] === parentId ); extractObj = parentObj['attached'][targetType].find( e=>e[targetType+'_id'] && e[targetType+'_id'] === targetId ); } // 抽出結果 return extractObj; } /* * 実行 ***************************************************/ // 親の抽出 ( media ) var result1 = get_extractObj( getObj(), 'library', 'media', '10' ); console.log('result1:',result1); // 親の抽出 ( comment ) var result2 = get_extractObj( getObj(), 'library', 'comment', '100' ); console.log('result2:',result2); // 子の抽出 ( media ) var result3 = get_extractObj( getObj(), 'timeline', 'media', '10', 'comment', '200' ); console.log('result3:',result3);

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jun68ykt

2019/09/29 05:10

こんにちは。 ご質問の意図を確認させてください。 現状では // 子の抽出 ( media ) var result3 = get_extractObj( getObj(), 'timeline', 'media', '10', 'comment', '200' ); と、get_extractObjの第5, 6 引数にて 'comment', '200' を渡すことで親オブジェクトを指定し、media_idが "10" のオブジェクトを探してくるのを、以下 var result3 = get_extractObj( getObj(), 'timeline', 'media', '10'); のように、親オブジェクトの指定なしでも、子要素含めて該当するオブジェクトがあれば、それを返すようにしたい ということでしょうか?
kuroean

2019/09/29 05:19

いつも不足ばかりでご迷惑おかけしてすみません。仰る通りです。親の指定をせず、引数が減った方がみやすいし早いかな?と思ったかんじです。
jun68ykt

2019/09/29 05:33

ご回答ありがとうございます。いえ。no problem です。 なるほどです。 それをふまえて、もう一点確認ですが、ご質問にあるコードにある getObj() で得られるオブジェクトを対象にして、 var result3 = get_extractObj( getObj(), 'timeline', 'media', '10'); とすると、media_id が "10" のオブジェクトは、 以下の2カ所にあります。 1) comment_id : 200 のオブジェクトの attached.media の中 2) comment_id : 300 のオブジェクトの attached.media の中 この場合、get_extractObj が返すオブジェクトとしては、上記 1) と 2) のいずれにするのか?について何か要件はありますでしょうか? または、どちらを返してもかまわない( = get_extractObj のアルゴリズムの中で、先に見つかった方を返す、など)のでしょうか?
kuroean

2019/09/29 05:51

あう、そうですよね。そこが抜けてました。先に見つかった方が得られればと思っています。2か所にあっても必ず同じデータになっているはずだからです。ということで、 1) と 2) についての指定はありません。 また何かございましたがいつでもご指摘くださいませ。
jun68ykt

2019/09/29 07:40

ご返信ありがとうございます。回答しましたので、参考になれば幸いです。(P.S. find はご自身のモノにしたんですね。あと => もお使いになっており、コードが進歩しているのを感じます)
guest

回答1

0

ベストアンサー

こんにちは

回答するにあたって、親と子の(最大)2階層に制限するのは汎用性がないと思われましたので、子もまた子を持っているかもしれないという構造を対象に考えました。そうすると、対象のオブジェクトの各area は、.attached.xxx によって子要素の配列を持つノードのツリー(木構造) として把握できます。ツリーのノードの中で、何らかの条件に合致するものを探すロジックは、再帰 関数を使えば書けます。

以下は get_extractObj の修正版です。 _recursive_search という再帰関数を作り、これを利用して該当する要素を見つけ出すコードです。

javascript

1function get_extractObj( targetObj, area, targetType, targetId) { 2 3 let extractObj; 4 5 const areaArray = targetObj['obj'][area]; 6 7 const _recursive_search = (ary) => { 8 if (!ary || ary.length === 0) return false; 9 10 return ary.some(e => { 11 if (e[`${targetType}_id`] === targetId) { 12 extractObj = e; 13 return true; 14 } else { 15 const children = e.attached && e.attached[targetType] 16 return _recursive_search(children); 17 } 18 }); 19 } 20 21 _recursive_search(areaArray) 22 23 // 抽出結果 24 return extractObj; 25}

なお、上記のCodePenのサンプルでは、media_id"10" の要素に、uniqId というプロパティを追加して、複数該当する場合にどれが該当オブジェクトとして取得されたかが分かるようにしています。

以下のサンプルは、該当する要素をもう1つ加えたものです。

上記では、comment_id"100" の要素からみると孫(子の子)にあたる深さの場所にmedia_id"10" の要素がありますが、これをget_extractObj は最初にみつけて extractObj に代入し、探索を終了します。このように、子要素があれば、それらを深掘りして探すほうを優先させる探し方を、深さ優先探索 といいます。

※ 実際の業務で、再帰関数を作る場合、無限ループになったりしないように、何らか再帰をストップさせる条件を明示的に追加するなどの注意が必要です。(たとえば、再帰呼び出しの深さが10になったら、それより深いところは探索させないようにする、など)

以上、参考になれば幸いです。

投稿2019/09/29 07:34

jun68ykt

総合スコア9058

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kuroean

2019/09/29 09:02

深さ優先探索ですか。まさにその概念を求めていました。ありがとうございます。そして相変わらずのクオリティ!!脱帽です。汎用性についてのお気遣いも完璧で、階層の深さへのご対応や、取得元のuniqIdを付けるというアイディアも恐れ入りました。いやぁもう…誠にありがとうございます。
jun68ykt

2019/09/29 12:52

どういたしまして。こちらこそ、毎回私の、いろいろ脱線しがちな、アレもコレも詰め込もうとする回答に、丁寧なご返事を頂き、ありがとうございます。益々の上達を祈念しております。草々
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問