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

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

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

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

Q&A

6回答

2348閲覧

二次元配列をグループ分けしてキー名をつけてオブジェクトに変換する方法

yahret45

総合スコア41

JavaScript

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

0グッド

0クリップ

投稿2020/07/02 21:45

編集2020/07/02 21:48

二次元配列をグループ分けしてキー名をつけてオブジェクトに変換する方法について質問します。
変数を下記のstartからgoalに変換したいと考えております。

const start = [ ["株式会社トヨタ", "システム利用料の件", "システム利用料", 1, "個", 1000000], ["株式会社トヨタ", "システム利用料の件", "その他費用1", 1, "個", 10000], ["株式会社HONDA", "システム利用料の件その2", "システム利用料", 1, "個", 5500000], ["株式会社HONDA", "システム利用料の件その2", "その他費用2", 1, "個", 10000], ]; const goal = { "株式会社トヨタ": { expenseTitle: "システム利用料の件", arrays: [ ["システム利用料", "", 1, "個", 1000000], ["その他費用1", "", 1, "個", 1000] ] }, "株式会社HONDA": { expenseTitle: "システム利用料の件その2", arrays: [ ["システム利用料", "", 1, "個", 5500000], ["その他費用2", "", 1, "個", 1000] ] } }

一度オブジェクトの連想配列に変換してから、Map()メソッドを使う方法でいけそうな気がしているのですが、
そもそもそのアプローチで良いのか、もっと良い方法があればご教授頂けると助かります。

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

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

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

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

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

think49

2020/07/03 11:21

考えるだけでコードを書かないのは、丸投げも同然です。 https://teratail.com/help/question-tips#questionTips1-2 > 一度オブジェクトの連想配列に変換してから、Map()メソッドを使う方法でいけそうな気がしているのですが 仮説を立てたなら、試してみればいいのでは? 試さないと分からないし、覚えられません。 私は間違っていると思いますが、失敗しないと分からないこともあります。
guest

回答6

0

こんにちは
ご質問に、

もっと良い方法があればご教授頂けると助かります。

とありましたので、配列やオブジェクトの操作で便利なライブラリlodash を使う方法を挙げます。使うメソッドは以下の2点です。

上記を使って、以下のように書けます。

javascript

1const goal = _(start) 2 .groupBy(0) 3 .mapValues(arrays => ( 4 { 5 expenseTitle: arrays[0][1], 6 arrays: arrays.map(array => [array[2], '', ...array.slice(3)]) 7 })) 8 .value(); 9

追記1

ただし、上記のコードでは、ある社名を持つarray のうち、startの先頭に近いものに含まれる第2番目の要素が、expenseTitle として使われます。ですので、もし例えば start が以下

const start = [ ["株式会社トヨタ", "システム開発費の件", "その他費用1", 1, "個", 1000000], ["株式会社トヨタ", "システム利用料の件", "システム利用料", 1, "個", 1000000], ["株式会社トヨタ", "システム利用料の件", "その他費用2", 1, "個", 10000] ];

のように、先頭要素の企業名は同じで2番目の要素が異なるarrayを含む場合であっても、expenseTitle としては、先頭に近い ["株式会社トヨタ", "システム開発費の件", "その他費用1", 1, "個", 1000000]"システム開発費の件" が使われて、goalは以下になります。

{ 株式会社トヨタ: { expenseTitle: "システム開発費の件", arrays: [ ["その他費用1", "", 1, "個", 1000000], ["システム利用料", "", 1, "個", 1000000], ["その他費用2", "", 1, "個", 10000] ] } }

もし、上記だと、ご要望と違ってしまう場合は、ご質問に追記いただくかコメント頂ければと思います。

追記2

lodash を使わずに、reduce を使ってもできます。

javascript

1const goal = start.reduce((obj, array) => { 2 const [company, expenseTitle, expenseDetail, ...rest] = array; 3 if (!obj[company]) { 4 obj[company] = { expenseTitle, arrays: [] }; 5 } 6 obj[company].arrays.push([expenseDetail, '', ...rest]); 7 return obj; 8}, {});

ただし、上記のコードも、追記1に書いたように、同じ企業名の明細データの中では、startの先頭に近いものに含まれる 第2要素が goalexpenseTitleとして使われます。

追記3

ご質問に書かれている要件の範囲を超えるものになりますが、先の追記1に対応する例を挙げておきます。ある一つの企業の明細データの中に、複数のexpenseTitleに相当する文字列が含まれる場合に対応するために、lodashのgroupByとmapValues を入れ子にして使います。

javascript

1const goal = _(start) 2 .groupBy(0) 3 .mapValues(arrays => 4 _(arrays) 5 .groupBy(1) 6 .mapValues(subArrays => subArrays.map(array => array.slice(2))) 7 .value() 8 ) 9 .value();

投稿2020/07/03 00:16

編集2020/07/03 06:40
jun68ykt

総合スコア9058

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

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

0

一度オブジェクトの連想配列に変換してから、Map()メソッドを使う方法

(中略) そもそもそのアプローチで良いのか

Map を使おうとお考えなら、オブジェクトの連想配列 を後で使う必要があるかを考え、
必要なさそうなら、ダイレクトにMapを作っても良いかもしれません。

javascript

1var goal = start.reduce( (map, [key, expenseTitle, ...others]) => ( 2 map.has(key) 3 ? map.get(key).arrays.push(others) 4 : map.set(key, {expenseTitle,arrays:[others]}) 5, map), new Map);

投稿2020/07/03 00:35

編集2020/07/03 00:41
AkitoshiManabe

総合スコア5434

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

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

YufanLou

2020/07/08 08:41

美しいコードをお見せいただきありがとうございます! コンマ演算子知りませんでした。勉強になりました!
guest

0

"Map()メソッドを使う方法"が見ないとこちらの方法は”もっと良い方法”かどうか知りませんよ〜

そもそもこんなデータ変換問題は領域によって一つ一つ違っていますし、通用な方法がありません。ただ、こちらはデータベースの関係型データをオブジェクトデータに変換してそうですが、オブジェクト関係マッピング(ORM)というの検索してみてください。けど、こちらの二重配列は関係型データとして正規化されていないので、ORMも対応してないと思います。

投稿2020/07/02 22:42

YufanLou

総合スコア463

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

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

0

JavaScript: [????, ????, ????, ????, ????, ????]のような配列を[[????, ????, ???? ], [????, ????, ????]]に仕分けする - Qiita
https://qiita.com/suin/items/25908e15aeaa7e3a1ae6#comment-39fdeb534519eebe5d10

上記のコメント欄で汎用的なgroup関数を書いたのでそちらを使って別回答しておきます。
出力結果は同じものです。

https://jsbin.com/togedojivo/5/edit?html,js,console

js

1const start = [ 2 ["株式会社トヨタ", "システム利用料の件", "システム利用料", 1, "個", 1000000], 3 ["株式会社トヨタ", "システム利用料の件", "その他費用1", 1, "個", 10000], 4 ["株式会社HONDA", "システム利用料の件その2", "システム利用料", 1, "個", 5500000], 5 ["株式会社HONDA", "システム利用料の件その2", "その他費用2", 1, "個", 10000], 6]; 7 8const group = (valueArray, groupFunc) => { 9 const result = { 10 index: [], 11 result: [], 12 }; 13 valueArray.forEach(v => { 14 const funcResult = groupFunc(v); 15 let index = result.index.indexOf(funcResult); 16 if (index === -1) { 17 result.index.push(funcResult); 18 index = result.index.length - 1; 19 result.result.push([]); 20 } 21 result.result[index].push(v); 22 }) 23 24 return result 25} 26 27const result = group(start, v => v[0]); 28const goal = {}; 29result.index.forEach((v, i) => goal[v] = { 30 expenseTitle: result.result[i][0][1], 31 arrays: result.result[i].map(e => [e[2], e[3], e[4], e[5]]) 32}); 33 34 35console.log(goal);

投稿2020/07/08 06:58

編集2020/07/08 07:02
standard-soft

総合スコア197

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

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

0

いわゆるデータの正規化ができていません

  • 株式会社トヨタに対するexpenseTitleが"システム利用料の件"
  • 株式会社HONDA 同上 "システム利用料の件その2"

が1対1である保証が必要です

投稿2020/07/03 00:40

yambejp

総合スコア115010

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

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

yambejp

2020/07/03 00:53

こんな感じ? const goal=start.reduce((x,y)=>{ x[y[0]]=x[y[0]]||{}; x[y[0]].expenseTitle=y[1]; x[y[0]].arrays=x[y[0]].arrays||[]; x[y[0]].arrays.push([y[2],y[3],y[4],y[5]]); return x; },{}); console.log(goal);
guest

0

一度オブジェクトの連想配列に変換してから、Map()メソッドを使う方法でいけそうな気がしているのですが

そちらでもよいと思います。

自分の方も書いてみました。

会社名と次の「システム利用料の件」の所が一致していないといけませんが、次のコードでデータ加工できました。

動作確認、こちらでできます。
https://jsbin.com/xodiyoziwu/5/edit?html,js,console

const start = [ ["株式会社トヨタ", "システム利用料の件", "システム利用料", 1, "個", 1000000], ["株式会社トヨタ", "システム利用料の件", "その他費用1", 1, "個", 10000], ["株式会社HONDA", "システム利用料の件その2", "システム利用料", 1, "個", 5500000], ["株式会社HONDA", "システム利用料の件その2", "その他費用2", 1, "個", 10000], ]; const goal = {}; start.forEach(data => { if (goal[data[0]] === undefined) { goal[data[0]] = { expenseTitle: data[1], arrays: [] } } goal[data[0]].arrays.push([data[2], data[3], data[4]]); }) console.log(goal);

投稿2020/07/06 01:08

編集2020/07/06 01:10
standard-soft

総合スコア197

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問