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

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

ただいまの
回答率

90.47%

  • JavaScript

    17012questions

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

【Javascript】2次元配列からピボットテーブル用に整形した配列を生成するロジック

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,367
退会済みユーザー

退会済みユーザー

# 目的
以下の様なCSVから2次元配列を作成後(サンプル1)、結果テーブルに組み込むために整形した2次元配列を生成したい。

CSVサンプル
Date,Category,A,B,C
2015/02,AAA,a,b,c
2015/02,BBB,d,e,f
2015/03,CCC,g,h,i
2015/03,BBB,j,k,l
2015/03,AAA,m,n,o

サンプル1
var csvArray = [ //サンプルのため値へのクォートは省略
   [2015/02,AAA,a,b,c],
   [2015/02,BBB,d,e,f],
   [2015/03,CCC,g,h,i],
   [2015/03,AAA,j,k,l]
];

結果テーブル
Table AAA              Table BBB              Table CCC
|   |2015/02|2015/03|  |   |2015/02|2015/03|  |   |2015/02|2015/03|
|:--|-------|------:|  |:--|-------|------:|  |:--|-------|------:|
| A |   a   |   j   |  | A |   d   |       |  | A |       |   g   |
| B |   b   |   k   |  | B |   e   |       |  | B |       |   h   |
| C |   c   |   l   |  | C |   f   |       |  | C |       |   i   |

生成したい配列サンプル
var table = [
   [AAA,a,j,b,k,c,l],
   [BBB,d,'',e,'',f,''],
   [CCC,'',g,'',h,'',i]
];

//オブジェクトでも構わない
var table = {
   'AAA':[a,j,b,k,c,l],
   'BBB':[d,'',e,'',f,''],
   'CCC':['',g,'',h,'',i]
};

## 前提条件
1. Javascript(jQuery等不可)使用
2. 配列の1次元目は行方向、2次元目は列方向とし、2次元目の長さはすべて同じ
3. データがないセルは空白('')とする
4. Categoryごとにテーブル(配列)をまとめる
5. 行列変換用の関数はmatrix(array)として定義されているものとする
(利用の有無は問わないが利用を前提とする)
6. tableの結果テーブル整形処理は実装済みとする


ピボットテーブル生成という表現が正しいかどうかは別としまして、
csvArrayから各テーブルにセットするための値をまとめたtableを生成するまでのロジックについて、
皆様のお知恵をお借りしたいと思っております。
サンプル通りの配列生成にこだわっているわけではございませんので、よろしくお願い致します。

## 補足
既に定義(実装)済みのmatrix関数は汎用化設計をしているという前提です。
単純に2次元配列を投げると行列変換された新しい2次元配列として返ってくるというものです。
要するにcsvArrayをtableに変換する過程において、必要ならばユーティリティーツールとしてご利用ください、といった感じです。

処理過程を文書にすると以下の様になります。

1. CSVから配列Aを生成
2. 配列Aを結果テーブル生成用に整形する(配列B)
3. 配列Bを結果テーブルとして整形

1、3の前後の処理ありきで、中間部分の2のロジックを求めています。
全体の構造は以下のようになっていると考えてください。

構造サンプル
var csvArray = csvToArray(csv);
/* ココカラ */

csvArrayをtableに変換する過程のロジックを求めています。

/* ココマデ */

// 以降、tableを結果テーブルに整形処理(実装済み) 

function csvToArray(csv){
   処理
  return array;//2次元配列を返す
}
function matrix(array){
   処理
   return newArray;//行列変換後の新しい2次元配列を返す
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

check解決した方法

0

自己解決、というより質問投稿する以前に持っていたイメージを再現したものです。
前後の処理は割愛しています。
以下のロジックでの最終出力結果はオブジェクトとなります。

var dateCol = matrix(csvArray)[0].filter(function(v,i,a){return (a.indexOf(v) == i);});//日付のユニーク配列(結果テーブルの列数としても利用(要+1))
var ctgry   = matrix(csvArray)[1].filter(function(v,i,a){return (a.indexOf(v) == i);});//カテゴリのユニーク配列(結果テーブル生成数としても利用)
var rows    = csvArray[0].length - 2;//結果テーブルのヘッダー行を除く必要行数
var table   = {};
var nAry    = new Array(rows).join("''").split("''");//必要列数分を空値で埋めた配列。列数が多い場合はforループで処理

/** 一旦カテゴリごとのオブジェクトにまとめる
見通しを良くするためfor文を重ねて泥臭く処理
ここでの肝はプロパティ値を2次元配列にすること
 */
for(var i = 0,l = dateCol.length; i < l; i++) {
  for(var j = 0,m = ctgry[0].length; j < m; j++) {
    for(var k = 0,n = csvArray.length; k < n; k++){
      if(csvArray[k].indexOf(dateCol[i]) >= 0 && csvArray[k].indexOf(ctgry[j]) >= 0){
        table[ctgry[j]] ?
          table[ctgry[j]].push(csvArray[k].slice(2)):
          table[ctgry[j]] = [csvArray[k].slice(2)];
        break;
      }
    }
    (k == n) && (table[ctgry[j]] ? table[ctgry[j]].push(nAry):table[ctgry[j]] = [nAry]);
  }
}

/** オブジェクトの整形 */
for(i in table){
  var ary  = matrix(table[i]);
  table[i] = ary.join(',').split(',');
  table[i].forEach(function(v,i,a){
    (v === void 0) && (v = "''");
  });
}

## 謝辞
htsign様、お忙しい中当方の質問へのご回答、ありがとうございました。
こちらで詳細を述べることはできませんが、その後仕様が若干変更され、求める配列の形式も変更となりました。
いただいた回答は今後の参考にさせていただきます。
ありがとうございました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/05/13 20:55

    for地獄ですね…。
    今回は私の力不足でお助けできず残念でしたが、また機会がありましたらお力添えさせていただければと思います。

    キャンセル

0

書いてるうちにややこしくなってしまいました。
// 重複排除メソッド
Array.prototype.distinct = function(){
    var ret = [];
    
    for (var i = 0, l = this.length; i < l; i++) {
        if (ret.indexOf(this[i]) !== -1) continue;
        ret.push(this[i]);
    }
    return ret;
};

var data = "\
Date,Category,A,B,C\n\
2015/02,AAA,a,b,c\n\
2015/02,BBB,d,e,f\n\
2015/03,CCC,g,h,i\n\
2015/03,BBB,j,k,l\n\
2015/03,AAA,m,n,o";

var csvArray = createCsvArray(data, true);
var table = matrix(csvArray);

function createCsvArray(/* string */ data, /* bool */ headerVisible) {
    headerVisible = !!headerVisible || false;
    
    var lines = data.split("\n");
    
    if (headerVisible) {
        lines.shift();
    }
    return lines.map(function(line){
        return line.split(",").map(quote);
    });
}

function matrix(/* array */ array) {
    // 2015/02, 2015/03 など、年月を取得
    var monthes = array.map(function(arr){ return arr[0] }).distinct().sort();
    // AAA, BBB など、カテゴリ名を取得
    var categories = array.map(function(arr){ return arr[1] }).distinct().sort();
    
    var table = {};
    categories.forEach(function(category){
        // targets はカテゴリ名に category を含んでいるもの
        var targets = array.filter(function(arr){ return arr[1] === category });
        table[category] = [];
        
        for (var i = 0; i < monthes.length; i++) {
            targets
            // 年月に montehs[i] を含むもののみ抽出
            .filter(function(arr){ return arr[0] === monthes[i] })
            // 先頭2つ(年月とカテゴリ名)を削る
            .map(function(arr){ return arr.slice(2) })
            .forEach(function(arr){
                for (var j = 0; j < arr.length; j++) {
                    table[category][j * monthes.length + i] = arr[j];
                }
            });
        }
        // undefined を '' に置き換え
        for (var i = 0; i < table[category].length; i++) {
            if (table[category][i] === void 0) {
                table[category][i] = "''";
            }
        }
    });
    
    return table;
}

function quote(text) {
    return "'" + text + "'";
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/05/05 18:36

    htsign 様

    ご回答頂きありがとうございます。
    確かにややこしく、こんがらがりますね。。。お疲れ様です。
    (特にmatorix内、filterからの、map、、からの、forEach、、、泣けてきます。)

    ただ、前提条件をもう少し詳しく記載しておけばよかったのかもしれませんが、
    いただいたご回答で申しますと、createCsvArray及びmatrixは既に実装済み、
    ということになります。
    (matrixの利用の有無は問いませんが)

    その上で、「csvArrayから各テーブルにセットするための値をまとめたtableを生成するまでのロジック」を求めておりますので、
    誠に申し訳ございませんが、厳密には当方の求める回答とは異なります。

    しかしながら、ロジックの方向性や私自身あまり頻繁には使わないmapの利用法など、今後も含め参考にさせていただきます。

    ありがとうございました。

    キャンセル

  • 2015/05/05 19:16

    理解力が足らなくて失礼いたしました…。
    > 行列変換用の関数はmatrix(array)として定義されているものとする
    ここを「定義されるものとする」と勝手に脳内変換してしまっていました。(実は条件を読み直すまで matrix関数は createTable関数 という名前にしていました)

    stshishoさんが必要としてらっしゃるのは変数 table からMarkdownで書かれたような結果テーブルを作るロジック、ということでしょうか?
    私は「変数 csvArray を 変数 table に変換するロジック」を指していると考えていました。

    キャンセル

  • 2015/05/06 12:41

    htsign 様

    > 私は「変数 csvArray を 変数 table に変換するロジック」を指していると考えていました。

    上記のご理解で間違いございません。
    厳密に何が求めているものと違うか、というのはmatrix内で「変数 csvArray を 変数 table に変換」している点です。
    詳しくは質問内容に補足として追加しましたが、既に実装されているmatrixをうまく使ってtableに変換したい、という内容です。

    なお、私自身も処理イメージをもっておりますが、他の方のロジックも参考にしたいと思い、質問させている次第です。

    キャンセル

  • 2015/05/06 13:07

    なるほど。そういうことでしたら、私の回答は「上記のmatrix関数の名前をcreateTableとしたもの」ということになります。
    その上で
    > 要するにcsvArrayをtableに変換する過程において、必要ならばユーティリティーツールとしてご利用ください
    については「使わない」という選択をしたものをお考えいただければと思います。
    stshishoさんも既にロジックはできているということですので、何かの参考にしていただければ幸いです。

    キャンセル

関連した質問

同じタグがついた質問を見る

  • JavaScript

    17012questions

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