質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.47%
JavaScript

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

Q&A

解決済

3回答

762閲覧

2重 For 構文の処理でうまくいかない

hitohito.pitcha

総合スコア64

JavaScript

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

0グッド

0クリップ

投稿2018/12/30 09:07

前提・実現したいこと

JavaScript のデータ抽出で困っています。
以下のような名前に関する配列データがあります。

name_mail=[["鈴木"],["田中"],["佐藤"],["池田"],["小林"],["村田"],["中野"],["山田"],["村西"],["坂本"]]
name_data=[["鈴木",1],["田中",2],["佐藤",3]]

上記配列に対して、name_mail の要素が
name_data のインデックス0に一致する場合は、
name data のインデックス1 を抽出したいという事を実現したいです。
例:name_mail に 鈴木があれば、1が欲しい(name_data のインデックス番号0)

上記配列であれば、抽出したい結果としては以下になります。
1鈴木
2田中
3佐藤

JavaScript で以下のスクリプトを実行しましたが、
欲しい出力結果にはなりません。

name_mail=[["鈴木"],["田中"],["佐藤"],["池田"],["小林"],["村田"],["中野"],["山田"],["村西"],["坂本"]] name_data=[["鈴木",1],["田中",2],["池田",3]] for(var i=0;i<11;i++){ for(var j=0;j<3;j++){ if(name_mail[i] == name_data[j][0]){ var name = name_data[j][0]; var to = name_data[j][1]; console.log((to+name)+ "\n" ); break; } else{ var name = "不明"; var to = 0; console.log(to+name); } } }

出力結果

1鈴木

0不明
2田中

0不明
0不明
3佐藤

0不明
0不明
0不明
0不明
0不明
0不明
0不明
0不明
0不明
0不明
0不明
0不明
0不明
0不明
0不明
0不明
0不明
0不明
0不明
0不明
0不明
0不明
0不明
0不明

不明時の実行をなくして、条件一致時だけ実行したいです。
このスクリプトを実施するにあたり、他プログラムに送信する仕組みを作っていまして、
無駄な送信が増えている状況です。

お手数ですが、ご教授の程、よろしくお願い致します。

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

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

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

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

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

guest

回答3

0

ベストアンサー

こんにちは。

いろいろなやり方がありそうですが、一例ということで、以下でどうでしょう?

javascript

1const name_mail = [["鈴木"], ["田中"], ["佐藤"], ["池田"], ["小林"], ["村田"], ["中野"], ["山田"], ["村西"], ["坂本"]]; 2const name_data = [["鈴木", 1], ["田中", 2], ["池田", 3]]; 3 4const map = new Map(name_data); 5 6name_mail.forEach(([name]) => { 7 if (map.has(name)) { 8 console.log(`${map.get(name)}${name}`); 9 } 10});

実行結果:

1鈴木

2田中
3池田

以下は、上記のコードを動作確認するために jsFiddle に上げたものです。

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

追記1

name_data に該当する要素がないものに対して 0不明 を出力させるようにするには、例えば以下

javascript

1name_mail.forEach(([name]) => { 2 const value = map.get(name) || 0; 3 const label = value ? name : '不明'; 4 console.log(`${value}${label}`); 5});

のようにするか、もしくは、shou6 さんがコメントでフォローして下さっているように、動作確認用サンプル(1) のコードの if (map.has(name)) に対する else を追加して、以下

javascript

1name_mail.forEach(([name]) => { 2 if (map.has(name)) { 3 console.log(`${map.get(name)}${name}`); 4 } else { 5 console.log('0不明'); 6 } 7});

のようにすればよいかと思います。

ただし上記のサンプル(2)または(3)だと、出力結果は、以下になります。

1鈴木

2田中
0不明
3池田
0不明
0不明
0不明
0不明
0不明
0不明

上記のように、 2田中3池田 との間に、1個の 0不明 が出力されますが、もし、これが望んでいる出力ではなく、

1鈴木

2田中
3池田
0不明
0不明
0不明
0不明
0不明
0不明
0不明

のように、

  • name_data に該当の要素があるものは、出力結果の先頭に連続して出力され、
  • かつ、それらはname_data に含まれる数値の昇順に並んでおり、
  • その後に該当なしのものに対応する、0不明 が出力される。

という順序を保って出力させたいのであれば、どこかで sort を使う必要があり、もう一工夫が必要ですね。一例として、以下のようにしてみました。

javascript

1const names = name_mail.map(([name]) => name); 2const m = new Map(name_data); 3 4const matched_ary = names 5 .filter(name => m.has(name)) 6 .sort((n1,n2) => m.get(n1) - m.get(n2)) 7 .map(name => `${m.get(name)}${name}`); 8 9const unmatched_ary = names 10 .filter(name => !m.has(name)) 11 .map(_ => '0不明'); 12 13matched_ary.concat(unmatched_ary).forEach(str => console.log(str));

なお、上記のサンプル(4)では、正しく動作するかの検証のために、最初に与えられた2つの配列

  • name_mail
  • name_data

を Lodash の shuffle でランダムに並び替えてから、結果を得るためのロジックを動かしていますが、望む結果になっていることが確認できると思います。

とはいえ上記のサンプル(4)では、matched_aryunmatched_ary の2つの配列を作って、結果の表示のために再度結合しておりやや回りくどいですね。これを回避するため、ソートキーとなるプロパティを別に追加して、name_dataから作ったマップに該当なしの場合、昇順でソートした時に後ろにくるように非常に大きな値を入れることにしました。それが以下です。

javascript

1const m = new Map(name_data); 2 3name_mail 4 .map(([name]) => ({ 5 name: m.has(name) ? name : '不明', 6 data: m.get(name) || 0, 7 order: m.get(name) || Number.MAX_SAFE_INTEGER 8 })) 9 .sort((e1,e2) => e1.order - e2.order) 10 .forEach(e => console.log(`${e.data}${e.name}`)); 11

追記2

ここまでに示した回答では、配列 name_data からMapを作っていましたが、 別案として、name_mailname_data の両方の配列が持つ内容をマージしたエントリを含むMapを作る方法を挙げます。

具体的には、以下の2条件

  • name_mail または name_data 、あるいは両方に含まれる名前(人名の姓)の全てをキーとして持つ。
  • 各キーに対する値としては、デフォルト値は 0 で、name_data に同じキーのエントリがあれば、その値とする。

を満たすMapオブジェクトを、

const name_data_map = new Map([...name_mail.map(e => [e[0], 0]), ...name_data]);

で作成できます。
この name_data_map は以下のような内容を持つMapオブジェクトになります。

Map { '鈴木' => 1, '田中' => 2, '佐藤' => 0, '池田' => 3, '小林' => 0, '村田' => 0, '中野' => 0, '山田' => 0, '村西' => 0, '坂本' => 0 }

これを使って、各エントリをご要望の形式で出力するには以下のようにします。(※ソート処理は加えていません。

name_data_map.forEach( (data, name) => console.log(`${data}${data ? name : '不明'}`) );

追記3

ここまでの回答では、forEach, map, filter および Map などを使用しましたが、ご質問に挙げられている二重のforループのコードを少し修正して、ご希望の出力を得ようとするならば、例えば以下のようにすればよいかと思います。

javascript

1const name_mail = [["鈴木"], ["田中"], ["佐藤"], ["池田"], ["小林"], ["村田"], ["中野"], ["山田"], ["村西"], ["坂本"]]; 2const name_data = [["鈴木", 1], ["田中", 2], ["池田", 3]]; 3 4for(let i=0; i < 11; i ++ ) { 5 let matched = false; 6 for(let j=0; j < 3; j ++ ) { 7 if (name_mail[i] == name_data[j][0]) { 8 matched = true; 9 console.log(`${name_data[j][1]}${name_data[j][0]}`); 10 break; 11 } 12 } 13 if (!matched) { 14 console.log('0不明'); 15 } 16}

修正の要点は以下の2点です。

  • 0不明 の出力は、内側のループ、for(let j=0; j < 3; j ++ ) {・・・} から抜けてから行う。
  • 内側のループで値が見つかったのか否かの結果を、ループから抜けた後に参照できるようにする。(上記のコードではそのために、matched というフラグを追加)

投稿2018/12/30 13:05

編集2019/01/03 03:23
jun68ykt

総合スコア9058

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

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

hitohito.pitcha

2018/12/30 15:19

大変申し訳ございません。 質問に誤解を与える伝え方がありました。 出力したい結果は以下になる場合はいかがでしょうか? 1鈴木 2田中 3佐藤 0不明 0不明 0不明 0不明 0不明 0不明 0不明
shou6

2018/12/30 16:38

書いてくださったコードを見て、ちゃんと自分で確認すると良いと思いますよ。 if (map.has(name)) { 上記の部分でname_dataに存在するかチェックをしていることがわかるかと思います。 ならば、elseで返ってくるものが不明に当たる部分ということはわかりますよね。
jun68ykt

2018/12/30 23:51

@hitohito.pitchaさん 回答のほうに追記しました。不明点あれば、またコメント頂ければと思います。
jun68ykt

2018/12/30 23:52

@shou6さん フォローありがとうございます。コメント頂きました else を使ったコードを回答に追記しました。
jun68ykt

2019/01/03 02:19

@hitohito.pitchaさん ご質問に挙げられている二重のforループを使ったコードに、なるべく少ない修正でご要望の出力を得る回答を追記3 に書きました。参考になれば幸いです。
hitohito.pitcha

2019/01/03 03:01

ご丁寧な回答、大変ありがとうござました! 希望通りの内容が実現できそうです。 分からない記述は勉強してみます。
jun68ykt

2019/01/03 03:10

@hitohito.pitchaさん > 希望通りの内容が実現できそうです。 とのことで、よかったです ????
guest

0

要件が追加されていきそうな気がしますが。

JavaScript

1const name_mail=[["鈴木"],["田中"],["佐藤"],["池田"],["小林"],["村田"],["中野"],["山田"],["村西"],["坂本"]]; 2const name_data=[["鈴木",1],["田中",2],["池田",3]]; 3const result = name_mail.reduce( ( pre, curr )=> { 4 const d = name_data.findIndex( e => e[ 0 ] === curr[ 0 ] ); 5 pre.push( d != -1 ? name_data[ d ] : [ '不明', 0 ] ); 6 return pre; 7}, [] ).sort( ( a, b )=> b[ 1 ] - a[ 1 ] ); 8console.clear(); 9console.log( result ); 10/* 110: (2) ["池田", 3] 121: (2) ["田中", 2] 132: (2) ["鈴木", 1] 143: (2) ["不明", 0] 154: (2) ["不明", 0] 165: (2) ["不明", 0] 176: (2) ["不明", 0] 187: (2) ["不明", 0] 198: (2) ["不明", 0] 209: (2) ["不明", 0] 21*/ 22```**動くサンプル:**[https://jsfiddle.net/c0f1usr9/](https://jsfiddle.net/c0f1usr9/)

投稿2018/12/30 16:08

kei344

総合スコア69444

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

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

0

name_mailのデータを勝手に加工してしまいましたが、この方式だとスマートに書けると思います。

javascript

1name_mail=["鈴木","田中","佐藤","池田","小林","村田","中野","山田","村西","坂本"]; 2name_data=[["鈴木",1],["田中",2],["池田",3]]; 3 4name_data.forEach(function(val) 5{ 6 if (name_mail.indexOf(val[0]) != -1) 7 { 8 console.log(val[0]+val[1]); 9 } 10});

投稿2018/12/30 10:02

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

hitohito.pitcha

2018/12/30 12:15

ご回答いただき、大変ありがとうございます。 name_mail の取得方法が質問時の記述になるため、 配列方法を変えずに、取得する方法はありますでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問