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

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

詳細はこちら
JavaScript

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

jQuery

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

Q&A

解決済

3回答

1843閲覧

JavaScriptの文字列一致で、配列が上書きされてしまいます。

LeCreuset

総合スコア15

JavaScript

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

jQuery

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

1グッド

1クリップ

投稿2019/12/31 08:26

###実現したいこと
下記targetsのうちoksを含むかどうかで区別して、目的であるrを作りたいです。

a1,a2b1,b2oksを含むためそれぞれのキーの配列に入れて、
c1,c2oksを含まないためerrorsに入れる、というのが目的のrになります。

js

1var targets = ['a1','a2','b1','b2','c1','c2']; 2var oks = ['a','b']; 3 4// 目的 5r = [ 6 a: ['a1','a2'], 7 b: ['b1','b2'], 8 errors: ['c1','c2'] 9];

###発生している問題
後の値しか配列に入りません。
下記のソースコードですが、OKな方はa2b2しか入らず、エラーの方はc2しか入らないということが問題です。
前の値a1b1c1も入れたいのですが、どのようにすべきでしょうか。

###該当のソースコード
.matchを使いoksを含むかどうかを区別しているのですが、うまくいっていないみたいです。

js

1var targets = ['a1','a2','b1','b2','c1','c2']; 2var oks = ['a','b']; 3 4let r = []; 5 6targets.forEach( target => { 7 8 oks.forEach( ok => { 9 10 if ( target.match(ok) ) { 11 r[ok] = []; 12 r[ok].push( target ); 13 }else{ 14 r['errors'] = []; 15 r['errors'].push( target ); 16 } 17 18 }); 19 20}); 21 22console.log( r );

##試したこと
含むかどうかの検証方法として.matchでなく.indexOfを用いましたができませんでした。

js

1 //if ( target.match(ok) ) { 2 if ( target.indexOf(ok) != -1) { 3 r[ok] = []; 4 r[ok].push( target ); 5 }else{ 6 r['errors'] = []; 7 r['errors'].push( target ); 8 }

以上のように区別の方法を変えても同じ結果であることから、ループに原因があるのではないかと思慮しています。

ですが、初期化して.pushする、という流れの何がいけないのかがわからず、ここに質問させて頂きました。

解決策についてアドバイス願えましたら幸いです。
宜しくお願い致します。

DrqYuto👍を押しています

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

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

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

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

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

guest

回答3

0

ベストアンサー

ループに原因があるのではないかと思慮

target.match() の引数に文字列を格納しています(正規表現でなければなりません)。

oks には、 必ず「最初の1字が格納される」のであれば、「試したこと」に記載されたコードの条件式を target.indexOf(ok) === 0target.charAt(0) === ok で試してみてください。
(この2つの関数についても MDN で再確認してください)

追記)
oks の評価は filter() を使ってはどうでしょうか。

  1. 求める結果が オブジェクトなので、r={} にする
  2. oks.forEach()tmp = oks.filter( s=>target.indexOf(s)!==-1 ) とする。
  3. tmp.length が 1 なら r[tmp[0]], 0 なら r[error]

初期化は r["hoge"] || (r["hoge"] = []);とする

投稿2019/12/31 08:33

編集2019/12/31 09:26
AkitoshiManabe

総合スコア5434

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

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

LeCreuset

2019/12/31 08:58

matchに渡すのが文字列というご指摘には納得です。ですがindexOfの方は文字列で平気ですよね。 ならばループに原因があるという点は間違っていないのではと考えてしまいますが、このあたりいかがでしょうか。 > 必ず「最初の1字が格納される」 というわけではないです。失礼しました。確かに最初の1文字であれば、indexOfは位置が返るのでその書き方も良いかもしれませんね。
AkitoshiManabe

2019/12/31 09:33

追記しました。 r はあくまでも配列でプロパティを付与したいのであれば、追記の 1. は無視してください。
think49

2019/12/31 11:26

To: LeCreuset さん > ですがindexOfの方は文字列で平気ですよね。 Array#indexOf は「完全一致」で検索しますが、期待している動作は「前方一致」もしくは「部分一致」です。 一方、String#indedxOf は「部分一致」です。
LeCreuset

2019/12/31 11:26

おお、こうですか。できましたできました。 https://jsfiddle.net/p8wmrx7s/ filterや初期化の方法など大変勉強になりました。いつもありがとうございます。
LeCreuset

2019/12/31 11:28

To: think49 さん なるほど。そのようなことはまったく知りませんでした。ありがとうございます。
guest

0

こんにちは

ご質問に挙げられているコードの問題点はすでに、他の回答者の方々が指摘されていますので、そちらを参考にして頂ければと思います。この回答では、参考までに、別の書き方を挙げます。reduceスプレッド構文を使います。

javascript

1var r = targets.reduce((obj, e) => { 2 const key = oks.includes(e[0]) ? e[0] : 'errors'; 3 obj[key] = [...(obj[key] || []), e]; 4 return obj; 5}, {});

参考になれば幸いです。

補足

もし、 oksの要素が、アルファベット一文字とは限らないのであれば、keyを確定する行を以下のようにします。

const key = oks.find(ok => e.startsWith(ok)) || 'errors';

投稿2019/12/31 10:42

編集2019/12/31 12:10
jun68ykt

総合スコア9058

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

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

LeCreuset

2020/01/01 05:24

申し訳ございません。内容を理解してからご返信しようと思っておりまして…結局reduceのMDNの最初の理解から躓きましたw高度なテクニックをありがとうございます。
jun68ykt

2020/01/02 13:07

どういたしまして。 ご質問のコードでは forEach が使われていますね。 ということは、「 for 文を使わないで、forEach を使ってみよう」と思いつくことはお出来になるものと思います。ですので、次に 、 「ここは、reduceの使い所だ」 と思いつくようになることは、適度な高さのハードルになると思います。これをクリアするには、次に ・何らかの配列targetsの要素を1個ずつループで取り出して、それらを反映したオブジェクト r を作る。 という場面に出会ったら、 今現在では、 const r = {}; targets.forEach( target => { と書いてしまうと思いますが、こう書かないで、reduce でうまく書けるか自信がなくても const r = targets.reduce((obj, e) => {    // TODO: ここにロジックを書く return obj; }, {}); まで、ひとまず書いてしまってから、 // TODO: ここにロジックを書く の部分をどうするか悩むようにします。 はじめは、 reduce でやろうとして、うまくいかないこともあると思いますが、一回でも書き切ることができると、次はもっと楽に書けるようになって、だんだんとモノにできるようになってきます。 reduceを自分の道具にできると、(読みやすさが損なわれることもありますが、)かなり短いコードで済ませることができるようになります。
guest

0

ここをr[ok]に配列が入ってるかどうかを確認してからすればよいです。

js

1r[ok] = [];

投稿2019/12/31 08:29

kei344

総合スコア69596

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

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

LeCreuset

2019/12/31 08:36

なるほど。あってもなくても初期化してしまっていたわけですね。 仰るようにlengthで確認のステップを加えてみたののが以下ですが「okがundfinedだ」というエラーにぶちあたってしまいました。 たびたび申し訳ございませんが、この場合の解決策はいかがでしょうか。 if ( target.indexOf(ok) != -1) { if( ! r[ok].length ){ r[ok] = []; } r[ok].push( target ); }else{ if( ! r['errors'].length ){ r['errors'] = []; } r['errors'].push( target ); }
kei344

2019/12/31 08:38

「JavaScript 変数 有無」「JavaScript 配列 有無」とかで検索してみてください。
LeCreuset

2019/12/31 08:53

まず「配列 有無」の方は .length であっていますよね? そして「変数 有無」ですが、これは以下2つ以外ですとどういった方法がいいでしょうか? シンプルに下記のチェックを挟んでも同じエラーですし、 if ( target.indexOf(ok) != -1) { if ( r[ok] ) { if( ! r[ok].length ){ r[ok] = []; } } r[ok].push( target ); } 下記の typeof でも同じエラー、という状態でして。 if ( target.indexOf(ok) != -1) { if (typeof r[ok] == 'undefined') { if( ! r[ok].length ){ r[ok] = []; } } r[ok].push( target ); }
kei344

2019/12/31 09:29

最初の物は変数に値が入っているときに、空だったら空配列を入れているが、入っていない時は何もしていない。(そもそも配列があるのに空配列を入れる意味は無い) 後者は変数に値が入っていないときに無いのにもかかわらずlengthプロパティを参照したからエラー。
LeCreuset

2019/12/31 11:29

混乱中です。難しいですね条件…。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問