- **前提・実現したいこと **
JavaScriptで、複数の配列データを一つのデータにまとめ、CSVに出力するコードを書いています。
CSVに出力するためのコードは、JavaScript のデータを CSV で保存する内容 を参考にしています。
今回、自分が出力したい配列データは以下の通りです。
var data1 = [ [1,'A'], [2,'B'], [3,'C'] ]; var data2 = [ [4,'D'], [5,'E'], [6,'F'] ];
- 実現したい表(CSV形式)
data1-num | data1-alpha | data2-num | data2-alpha |
---|---|---|---|
1 | "A" | 4 | "D" |
2 | "B" | 5 | "E" |
3 | "C" | 6 | "F" |
- 改善したい点
上記の二つの配列データを一つのデータにまとめるにあたり、以下のコードを書いたのですが、配列の要素数が多くなっても対応できるような、もっと簡潔な書き方はないでしょうか。
var data = [ {'data1-num': data1[0][0],'data1-alpha': data1[0][1],'data2-num': data2[0][0],'data2-alpha': data2[0][1]}, {'data1-num': data1[1][0],'data1-alpha': data1[1][1],'data2-num': data2[1][0],'data2-alpha': data2[1][1]}, {'data1-num': data1[2][0],'data1-alpha': data1[2][1],'data2-num': data2[2][0],'data2-alpha': data2[2][1]}, ];
プログラミング初心者なもので非常に効率の悪いコードしか書けず、大変お恥ずかしいのですが、ご教授いただければ幸いです。
- みなさま、ご回答ありがとうございました!
どの方の回答も発見と驚きの連続で、ベストアンサーを決めるのが大変難しかったです。初心者のわたくしに、真摯に対応してくださり、大変感動しております。ありがとうございました。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/07/12 16:36
回答5件
0
こんにちは。
この回答では、まず、ご質問に挙げられている、オブジェクトの配列 var data
と同じ内容の配列を作るためのコードを挙げます。その後、追記にて、よりCSVに近い配列を作るコードを示します。
ご質問の要件のうち、今後、何が変わる可能性があるのか?によって、書くコードが変わってくると思います。ご質問に挙げられている与件から、今後どうなる可能性があるのかを思いつくままに挙げてみると、以下が思いつきます。
ご質問に挙げられているコードでは、
data1
とdata2
しかないが、data3
,data4
... と増える可能性がある。data1
とdata2
はともに要素の数が3で同じだが、いつも同じとは限らない。data1
およびdata2
の要素は、どれも長さが2の配列であるが、今後、3以上になるかもしれない。(つまり、num
,alpha
の次のサフィックスが追加されるかもしれない)data1
およびdata2
の要素である配列は、どれも長さが2で同じ長さであるが、常にすべてが同じ長さとは限らない。
上記のような可能性が考えられますが、これらのうち、今後、何が変わるかもしれないのか(または、変わらないのか)がはっきりしていると、リファクタの方向性が決まります。
以下は、上記の可能性のどれであっても、修正すべき箇所がなるべく分かりやすいように、という考え方で作成したコードです。このコードで作られる data
は、ご質問にある data
と同じ内容の配列になります。
javascript
1const data1 = [ 2 [1,'A'], 3 [2,'B'], 4 [3,'C'] 5]; 6 7const data2 = [ 8 [4,'D'], 9 [5,'E'], 10 [6,'F'] 11]; 12 13const toObj = (ary, prefix) => ({ 14 [`${prefix}-num`]: ary[0], 15 [`${prefix}-alpha`]: ary[1] 16}); 17 18const dataObj = { data1, data2 }; 19 20const tmp = Object.entries(dataObj).map(([k, ary]) => ary.map(e => toObj(e, k))); 21 22const data = tmp[0].map((e,i) => ({...e, ...tmp[1][i]})); 23 24console.log(data); 25 26
- 動作確認用のサンプル: https://jsfiddle.net/jun68ykt/3w4je19o/4
以上、参考になれば幸いです。
追記
CSV を作るためにより適した配列ということでいえば、ご質問のコードにある data
とは違う配列になりますが、以下のような配列のほうがよりCSVに近いと思います。
javascript
1[ 2 ["data1-num", "data1-alpha", "data2-num" ,"data2-alpha"], 3 [1,"A",4,"D"], 4 [2,"B",5,"E"], 5 [3,"C",6,"F"] 6]
そこで、上記のような配列を得るための、以下のような関数を作成しました。
javascript
1function makeCSVData(dataObj, columns) { 2 const keys = Object.keys(dataObj).sort(); 3 4 const lengths = keys.reduce((m, k) => m.set(k, Math.max(...dataObj[k].map(ary => ary.length))), new Map()); 5 6 const header = keys.reduce((ary, k) => 7 ary.concat([...Array(lengths.get(k))].map((_, i) => `${k}-${columns[i]}`)), []); 8 9 const numRows = Math.max(...Object.values(dataObj).map(ary => ary.length)); 10 11 const data = [...Array(numRows)].reduce((ary, _, i) => { 12 ary.push(keys.reduce((a, k) => 13 a.concat( 14 dataObj[k][i] ? 15 [...dataObj[k][i], ...Array(lengths.get(k) - dataObj[k][i].length ) ] : 16 [...Array(lengths.get(k))] 17 ) ,[])); 18 return ary; 19 }, 20 [header]); 21 22 return data; 23}
上記の関数 makeCSVData
は以下のように使います。
javascript
1const data1 = [ 2 [1,'A'], 3 [2,'B'], 4 [3,'C'] 5]; 6 7const data2 = [ 8 [4,'D'], 9 [5,'E'], 10 [6,'F'] 11]; 12 13const data = makeCSVData({ data1, data2 }, ['num', 'alpha']);
- 上記の動作確認用のサンプル: https://jsfiddle.net/jun68ykt/c0u1vp87/11/
この回答の冒頭に、入力データの様々な拡張性について書きましたが、上記の関数 makeCSVData
はそれらに対応しており、 以下のような入力でも適切に処理してCSV用のデータを生成します。
javascript
1const d1 = [ 2 [1,'A'], 3 [2,'B'], 4 [3,'C'], 5 [-1,'a'] 6]; 7 8const d2 = [ 9 [4,'D', true], 10 [5,'E'], 11 [6,'F', false, 100] 12]; 13 14const d3 = [ 15 [7,'X'], 16 [8,'Y'], 17 [9,'Z'], 18 [-7, 'x'], 19 [-8, 'y'] 20]; 21 22const data = makeCSVData({ d1, d2, d3 }, ['num', 'alpha', 'beta', 'gamma']);
- 上記の動作確認用のサンプル: https://jsfiddle.net/jun68ykt/c0u1vp87/10/
関数 makeCSVData
は、ご質問で提示された与件の範囲をかなり超えた大袈裟なものになってしまいましたが、先の様々な入力の拡張に対応させようとすると、こういうコードになるという一例として参考にして頂ければと思います。
投稿2019/07/13 06:37
編集2019/07/14 02:33総合スコア9058
0
reduce
を使用すればもっと簡潔に書けます。
下記のコードであれば記述が明快なので
moroheyさんが見たときにわかりやすいかと。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
js
1var data1 = [ 2 [1,'A'], 3 [2,'B'], 4 [3,'C'] 5]; 6 7var data2 = [ 8 [4,'D'], 9 [5,'E'], 10 [6,'F'] 11]; 12 13var data = data1.reduce((a, c, i) => { 14 a.push({ 15 'data1-num': c[0], 16 'data1-alpha': c[1], 17 'data2-num': data2[i][0], 18 'data2-alpha': data2[i][1] 19 }); 20 return a; 21}, []); 22 23console.log(data); 24// 0: {data1-num: 1, data1-alpha: "A", data2-num: 4, data2-alpha: "D"} 25// 1: {data1-num: 2, data1-alpha: "B", data2-num: 5, data2-alpha: "E"} 26// 2: {data1-num: 3, data1-alpha: "C", data2-num: 6, data2-alpha: "F"}
投稿2019/07/13 01:26
総合スコア2937
0
なんとなくリンク先をみて配列でもできそうだと思ったので形式が違いますが、こういうのを考えました
javascript
1var data1 = [ 2 [1,'A'], 3 [2,'B'], 4 [3,'C'] 5]; 6 7var data2 = [ 8 [4,'D'], 9 [5,'E'], 10 [6,'F'] 11]; 12const zipped = data1.map((e,i)=> e.concat(data2[i])); 13const header = [zipped[0].map((e,i) => `data${(Math.floor(i /2) + 1)}-${(i%2?"alpha":"num")}`)]; 14console.log(header.concat(zipped));
投稿2019/07/12 23:10
総合スコア12705
0
ベストアンサー
js
1var data1 = [ 2 [1,'A'], 3 [2,'B'], 4 [3,'C'] 5]; 6 7var data2 = [ 8 [4,'D'], 9 [5,'E'], 10 [6,'F'] 11]; 12 13var result = [], key, func = ( v, i ) => { 14 if ( !result[ i ] ) result[ i ] = {}; 15 result[ i ][ key + '-num' ] = v[ 0 ]; 16 result[ i ][ key + '-alpha' ] = v[ 1 ]; 17}; 18 19key = 'data1'; 20data1.forEach( func ); 21key = 'data2'; 22data2.forEach( func ); 23 24console.dir( result ); 25```**動くサンプル:**[https://jsfiddle.net/kscu5yhf/](https://jsfiddle.net/kscu5yhf/) 26 27--- 28 29【Array.prototype.forEach() - JavaScript | MDN】 30[https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)
投稿2019/07/12 16:46
総合スコア69400
0
二次元配列
こちらのコードは二次元配列をサポートしているようです。
二次元配列は可搬性が高く、CSV形式とも親和性の高い形式です。
JavaScript
1'use strict'; 2function arraysToArray (...arrayList) { 3 const results = []; 4 5 for (let array of arrayList) { 6 for (let j = 0, len = array.length; j < len; ++j) { 7 const cells = results[j] || (results[j] = []); 8 cells.push(...array[j]); 9 } 10 } 11 12 return results; 13} 14 15var data1 = [ 16 [1,'A'], 17 [2,'B'], 18 [3,'C'] 19]; 20 21var data2 = [ 22 [4,'D'], 23 [5,'E'], 24 [6,'F'] 25]; 26 27data1.unshift(['data1-num','data1-alpha']); 28data2.unshift(['data2-num','data2-alpha']); 29 30const array = arraysToArray(data1, data2); 31 32console.table(array);
ヘッダ行
前コードでは、tableのヘッダ行を unshift
で付け足していますが、本来、データと紐づくべき情報なので、予め、dataに入れておくか、別オブジェクトで関連付けを作る仕組みがあると良いと思います。
Re: morohey さん
投稿2019/07/13 08:19
総合スコア18162
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。