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

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

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

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

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

Q&A

5回答

7363閲覧

JSでオブジェクトのキーが同じ項目の配列を結合したい

van-0215

総合スコア89

JavaScript

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

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

0グッド

3クリップ

投稿2019/07/05 02:48

下記のようなオブジェクトをもつ配列 fees があったとします。
この配列を nameが同じものでdescriptionを配列にまとめる ようなプログラムを書きたいです。

JavaScript

1fees: [ 2 { 3 name: '特別', 4 description: `3,000円`, 5 }, 6 { 7 name: '特別', 8 description: `100,000円`, 9 }, 10 { 11 name: 'ロイヤル', 12 description: 'ロイヤル1', 13 }, 14 { 15 name: '特別', 16 description: `6,000円`, 17 }, 18 { 19 name: '普通', 20 description: '普通1', 21 }, 22 { 23 name: 'ロイヤル', 24 description: 'ロイヤル2', 25 }, 26 { 27 name: '普通', 28 description: '普通2', 29 }, 30 ],

関数 stateBind(fees) を通した feesは以下のように形になっていて欲しいです。

JavaScript

1fees: [ 2 { 3 name: '特別', 4 description: [`3,000円`, `100,000円`, `6,000円`], 5 }, 6 { 7 name: 'ロイヤル', 8 description: ['ロイヤル1', 'ロイヤル2'], 9 }, 10 { 11 name: '普通', 12 description: ['普通1', '普通2'] 13 }, 14 ],

やり方がわかりません。教えていただけると幸いです。よろしくお願いいたします。

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

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

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

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

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

yambejp

2019/07/05 05:36

nameが1つしか無いものは文字列で返すのでしょうか?一つだけ入った配列で返すのでしょうか?
guest

回答5

0

まぁ今回のケースは確かに配列→配列なので、
まともに戦うと相当辛いでしょう。

私のような上級者になればLodashなど使わなくてもreduceで一撃ですけど、
相応にコードが汚れるので「日本語でおk」と言いたくなることでしょう。


というわけで値の加工がしたければLodashを覚えてください。
このやり方は関数型言語を始めとする多くのモダンな言語へ持っていける概念です。

つまり、Lodashの機能を全て読み込む事でモダンなエンジニアとしての能力が開花します。

nameが同じものでdescriptionを配列にまとめる

LodashではgroupByという機能で実現できます。
Online Lodash Testerで挙動を確認できます。

JavaScript

1// _.groupBy(配列, fn) 2// fn: 戻り値が文字列になる関数 3 4const fees = [ 5 {name: '特別', description: `3,000円`}, 6 {name: '特別', description: `100,000円`}, 7 {name: 'ロイヤル', description: 'ロイヤル1'}, 8 {name: '特別', description: `6,000円`}, 9 {name: '普通', description: '普通1'}, 10 {name: 'ロイヤル', description: 'ロイヤル2'}, 11 {name: '普通', description: '普通2'}, 12]; 13result = _.groupBy(fees, it => it.name);

JSON

1{ 2 "特別": [ 3 { 4 "name": "特別", 5 "description": "3,000円" 6 }, 7 { 8 "name": "特別", 9 "description": "100,000円" 10 }, 11 { 12 "name": "特別", 13 "description": "6,000円" 14 } 15 ], 16 "ロイヤル": [ 17 { 18 "name": "ロイヤル", 19 "description": "ロイヤル1" 20 }, 21 { 22 "name": "ロイヤル", 23 "description": "ロイヤル2" 24 } 25 ], 26 "普通": [ 27 { 28 "name": "普通", 29 "description": "普通1" 30 }, 31 { 32 "name": "普通", 33 "description": "普通2" 34 } 35 ] 36}

これだけでは目的の値にはなりませんが、
特定のルールに従った配列を作るという目的では確実に前進しています。
引き続き別の値加工を行うために次の章へ行きましょう。


JavaScriptはそもそもArray->Arrayであればmapというメソッドがあるので簡単に加工出来るのですが、
groupByで作った値はオブジェクトなのでmapメソッドを所持していません
まぁ、Object.entries()等は持っていますから配列を経由してやれば良いだけなのですが……

Lodashを利用する場合は、
オブジェクトに対してもmapが使えます。
カテゴリが配列を示すListではなく、オブジェクトも両対応のCollectionになっている所からも分かります。

また、Lodashは_.メソッド(値, fn)で数珠つなぎにするとコードが非常に汚くなるので、
チェーン記法に対応しています。

JavaScript

1const fees = [ 2 {name: '特別', description: `3,000円`}, 3 {name: '特別', description: `100,000円`}, 4 {name: 'ロイヤル', description: 'ロイヤル1'}, 5 {name: '特別', description: `6,000円`}, 6 {name: '普通', description: '普通1'}, 7 {name: 'ロイヤル', description: 'ロイヤル2'}, 8 {name: '普通', description: '普通2'}, 9]; 10result = _.chain(fees) 11 .groupBy(fee => fee.name) 12 .map((fees, name) => ({ 13 name: name, 14 description: fees.map(fee => fee.description) 15 })) 16 .value();

JSON

1[ 2 { 3 "name": "特別", 4 "description": [ 5 "3,000円", 6 "100,000円", 7 "6,000円" 8 ] 9 }, 10 { 11 "name": "ロイヤル", 12 "description": [ 13 "ロイヤル1", 14 "ロイヤル2" 15 ] 16 }, 17 { 18 "name": "普通", 19 "description": [ 20 "普通1", 21 "普通2" 22 ] 23 } 24]

【おまけ】 reduceで一撃

まぁ、groupByのパターン知ってるエンジニアなら楽勝ですね。
reduceで似たようなものを再現するだけです。
(for文でちくちくやっても良いですが、状態変数が増えて読みづらくなるので一長一短)

ついでに配列ではなくdescriptionの文字列を抜き出した配列を作ってしまえば計算量が減ります。
さらっと書けるようになるためにもLodashは覚えて損はありません。
ぜひ

JavaScript

1const fees = [ 2 {name: '特別', description: `3,000円`}, 3 {name: '特別', description: `100,000円`}, 4 {name: 'ロイヤル', description: 'ロイヤル1'}, 5 {name: '特別', description: `6,000円`}, 6 {name: '普通', description: '普通1'}, 7 {name: 'ロイヤル', description: 'ロイヤル2'}, 8 {name: '普通', description: '普通2'}, 9]; 10const result = Object.entries( 11 fees.reduce((obj, fee) => { 12 if (obj[fee.name] == null) obj[fee.name] = []; 13 obj[fee.name].push(fee.description); 14 return obj; 15 }, {}) 16).map(([name, description]) => ({name, description})); 17 18console.log(JSON.stringify(result, null, 2));

JSON

1[ 2 { 3 "name": "特別", 4 "description": [ 5 "3,000円", 6 "100,000円", 7 "6,000円" 8 ] 9 }, 10 { 11 "name": "ロイヤル", 12 "description": [ 13 "ロイヤル1", 14 "ロイヤル2" 15 ] 16 }, 17 { 18 "name": "普通", 19 "description": [ 20 "普通1", 21 "普通2" 22 ] 23 } 24]

投稿2019/07/05 06:37

miyabi-sun

総合スコア21158

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

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

0

こんな感じではないでしょうか。

feesをループで回して、nameをキー、descriptionを値として持つ単独のオブジェクトを作る。その際、すでにキーが存在するなら、すでにある値の配列に要素を追加する。
オブジェクトができたら、Object.keysでループを回して、オブジェクトの配列にする。

わからない部分があったらコメントしてください。

投稿2019/07/05 03:09

Lhankor_Mhy

総合スコア36074

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

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

0

以下のコードで実現できます。
重複しない名前の配列を用意し、Array.prototype.map()メソッドで各要素を変換するようなイメージです。

javascript

1const fees = [ 2 { 3 name: '特別', 4 description: `3,000円`, 5 }, 6 { 7 name: '特別', 8 description: `100,000円`, 9 }, 10 { 11 name: 'ロイヤル', 12 description: 'ロイヤル1', 13 }, 14 { 15 name: '特別', 16 description: `6,000円`, 17 }, 18 { 19 name: '普通', 20 description: '普通1', 21 }, 22 { 23 name: 'ロイヤル', 24 description: 'ロイヤル2', 25 }, 26 { 27 name: '普通', 28 description: '普通2', 29 }, 30]; 31 32var result = Array.from(new Set(fees.map(v => v.name))).map(name => { 33 return { 34 name: name, 35 description: fees.filter(fee => fee.name === name).reduce((descriptions, cur) => { 36 descriptions.push(cur); 37 return descriptions; 38 }, []), 39 } 40}); 41 42console.log(result);

投稿2019/07/05 04:32

編集2019/07/05 04:46
foobar810

総合スコア217

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

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

0

配列に拘りがなければ、短く、かつ検索コスト(name,description値で検索にかかる時間)を下げる書き方があります。

JavaScript

1const map = new Map; 2 3for (let {name, description} of fees) map.has(name) ? map.get(name).add(description) : map.set(name, new Set(description));

Re: van-0215 さん

投稿2019/07/05 09:48

think49

総合スコア18162

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

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

0

丸投げ質問は非推奨ですが気が向いたので回答します。

js

1const fees = [ 2 { 3 name: '特別', 4 description: `3,000円`, 5 }, 6 { 7 name: '特別', 8 description: `100,000円`, 9 }, 10 { 11 name: 'ロイヤル', 12 description: 'ロイヤル1', 13 }, 14 { 15 name: '特別', 16 description: `6,000円`, 17 }, 18 { 19 name: '普通', 20 description: '普通1', 21 }, 22 { 23 name: 'ロイヤル', 24 description: 'ロイヤル2', 25 }, 26 { 27 name: '普通', 28 description: '普通2', 29 }, 30] 31 32const res = [] 33 34for (const fee of fees) { 35 const item = res.find(item => fee.name === item.name) 36 if (res.find(item => fee.name === item.name)) { 37 item.description.push(fee.description) 38 continue 39 } 40 41 res.push({ 42 ...fee, 43 description: [fee.description], 44 }) 45} 46 47console.log(res)

投稿2019/07/05 03:02

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問