こんにちは。
いろいろなやり方がありそうですが、一例ということで、以下でどうでしょう?
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つの配列
を Lodash の shuffle でランダムに並び替えてから、結果を得るためのロジックを動かしていますが、望む結果になっていることが確認できると思います。
とはいえ上記のサンプル(4)では、matched_ary
と unmatched_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_mail
とname_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 15:19
2018/12/30 16:38
2018/12/30 23:51
2018/12/30 23:52
2019/01/03 02:19
2019/01/03 03:01
2019/01/03 03:10