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

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

ただいまの
回答率

89.13%

スプレッドシート:①判定 ②指定した数の変数を動的に生成したい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,262

kusunoki

score 17

アドバイスを頂き、質問を3つに分割させていただきました。

実現したいこと

test2の要素それぞれをtest3の要素と一致するか判定し、test3にその値を入れたい。(test3はシート1のA列)

そのためにtest2の要素数分の変数(配列)を宣言したい。

ex.
test2の要素が2016/05/11,2016/05/14,2016/05/15のとき、

test3が2016/05/11 エラー,2016/05/14 エラー,2016/05/14 A,2016/05/15 B
test3に入っているすべての要素(日付の含まれるテキスト)全てに対して、test2の要素2016/05/11 2016/05/14 2016/05/15それぞれが含まれるか判定したい。
そして
2016/05/11を含むなら、ary_1へ 2016/05/11 エラー
2016/05/14を含むなら、ary_2へ 2016/05/14 エラー,2016/05/14 A
2016/05/15を含むなら、ary_3へ 2016/05/15 B
をpushしたい。

さらに、この日付部分は後にシートの名前やメールタイトルにしたいです。
配列の値は改行を加えた本文や、セルの値として使用していきたいです。

試したこと

1-1,test2の要素数分の配列を宣言

var count2 = test2.length;
  for(var i=1;i<=count2;i++){
    eval('var ary_' + i -1+ '=[];'); 
      }
  Logger.log(ary_1);

  

1-2,配列test2の要素それぞれに、test3の要素それぞれが一致するか判定して、1-1で作った配列に入れたい。

var maxRow=Sheet01.getDataRange().getLastRow();

var test3 = Sheet01.getRange(1,1,maxRow,1).getValues(); 
var count3 = test3.length;


for(var i=1;i<=count2;i++){
                var date = test2[i];
    for(var j=0;j<count3;j++){

         var g = test3[j].match(date);
         if(g != null){
        eval('ary_'+ i-1 +'.push(g)');
            }
     }
}


1-3,セルに1-1~1-2で作ったそれぞれのary_1~xの値を使用したい

  for(var i=1;i<=count2;i++){
     eval('var mailtext = ary_' + i-1 + ';'); /*例. var mailtext = ary_1;*/
     eval('var count4 = ary_' + i-1 + '.length;');

/*test2の個数だけ日付のシートを左端に作成して要素をA列にセットしたい*/
    for(var j=1;j<=count2;j++){
    SpreadsheetObject.insertSheet(test2[i])
       `Sheet0`2+i-1`+`.getRange(A,A).setValues(ary_`+i);
   }


/*test2の個数だけary_xそれぞれのメールを送信したい*/
    for(var q=1;q<=count2;q++){
    eval(`GmailApp.sendEmail("~~~~@~~~.com",test[i]+"分",ary_`+q+`);`);
     }

}

結果

1-1,これでは重複が除けませんでした。
var test = [2017/05/11,2017/05/14,2017/05/14,2017/05/15];
とすれば動きますが、範囲はかわるためシートから取得したいです。

1-2,
eval();を使用した生成ができない。
また、eval()は使用するべきではないとも聞きます。他に方法があるのでしょうか。

1-3,
出来ませんでした。

参考

http://qiita.com/htano/items/2476c7f616bed531e2f3

補足

実際使用するtest2やtest3のデータは
シートからgetRange().getValues()でもってきたもので、になります。

進行状況  教えていただいたどちらも試しています

A,配列を使用する方法
coco_bauerさんにいただいたアドバイスから

var test2 = Sheet03.getRange(2,1,maxRow).getValues(); 
var c2 = test2.length;

var test3 = Sheet03.getRange(2,2,maxRow).getValues(); 
var c3 = test3.length;

var ary = [];


 for(var i=0;i<c3;i++){
     var date = test3[i];
     var ary[i] = [];

     for(var j=0;j<c2;j++){        
        var res = test2[j].match(date);

         if(res != null){
            ary[i].push(date)
            }      

         }
     }   


としてみました。
しかし、
matchのところで、「オブジェクト[2017/05/11 21:53:43]A1で関数matchが見つかりません。」となり、
var ary[i] = [];の箇所で配列の中に配列を作ろうとすると「ステートメントの前に;がありません。」
となってしまいます。
(多次元配列 参考:http://hakuhin.jp/js/array.html#ARRAY_04 https://www.ajaxtower.jp/js/array/index5.html)

B,kei344さんに教えていただいたものも理解したいため、調べながら試しています。

  var test2 = [ '東京', '神奈川', '千葉' ];
  var test3 = [ '東京都千代田区', '東京都世田谷区', '神奈川県川崎市', '千葉県柏市' ];


データが上記のような場合
Logger.log(res)
{神奈川=[神奈川県川崎市], 東京=[東京都千代田区, 東京都世田谷区], 千葉=[千葉県柏市]}
Logger.log(res["東京"])
[東京都千代田区, 東京都世田谷区]
と出来たのですが、実際使用する日付型のデータだと出来ないでいます。
実際日付を扱うため、並びも日付順(もとのまま)であって欲しいです。

この後以下の処理をしたい

続けて、内容をテキストファイルとして書き出したり、シートを生成したり、メールとして自動送信する際にここで作った値を使用したいのです。

メール、最初の例のデータの場合
<タイトル>
2016/05/14
<本文(1つずつ改行する)>
2016/05/14 エラー
2016/05/14 A

日付型データでの処理がうまくいかないため、現在はまだ、先程の都道府県のデータで試しているのですが、実現出来ていません。データが追加されるたびに送信されてしまったり、送信順が日付順ではなくなってしまうのです。また、後からループなどで扱おうとした際にres["東京"]など、数字で指定できないのです。
そこでメールの自動送信を諦めて、まず日付ごとに振り分けたデータをその日付毎にシートや別ファイルとして書き出すことにとどめようかと考えています。
しかしシートを日数データ分の数十~数百個も作成するわけにも行かず悩んでいます。

今回の質問はこのために考えた工程だったのですが、遠回りしていますでしょうか。

メッセージ

解決までまだまだ時間がかかりそうです。スコア等皆様ご迷惑おかけします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • coco_bauer

    2017/05/24 14:34

    変数を生成しようとするから苦労しているように見えます。aryという配列を定義して、ary[0]をary_1,ary[1]をary_2,ary[2]をary_3だと思って使えば良いのでは?

    キャンセル

  • kusunoki

    2017/05/24 17:28

    配列の中に配列を入れるというのがよくわからなくて。こちらを使った方法も試してみます。ありがとうございます。

    キャンセル

回答 1

checkベストアンサー

+1

とりあえず重複を拾ってみるコードを。GASで使えるのがES6相当であればもう少しきれいにかけるはず。データの処理については、ブラウザで動くJavaScriptを書いてからGASに組み込んでみてはいかがでしょう。

var res = {}, i, l, tmp, key;
var test2 = [ '2016/05/11', '2016/05/14', '2016/05/15' ];
var test3 = [ '2016/05/11 エラー', '2016/05/14 エラー', '2016/05/14 A', '2016/05/15 B' ];

for( i = 0, l = test2.length; i < l ; i++ ) {
    res[ test2[ i ] ] = [];
}
for( i = 0, l = test3.length; i < l ; i++ ) {
    tmp = test3[ i ];
    for ( key in res ) {
        if ( !res.hasOwnProperty( key ) || tmp.indexOf( key ) == -1 ) { continue; }
        res[ key ].push( tmp );
    }
}
console.dir( res ); // ブラウザのデベロッパーツールで確認する場合

動くサンプル:https://jsfiddle.net/45a7hvdg/

// 上記結果を使うとき
for ( key in res ) {
    if ( !res.hasOwnProperty( key ) ) { continue; }
    console.log( res[ key ] ); // 配列
}

追記:

hasOwnProperty

【JavaScriptのループについて(オブジェクト編) - Tomcky's blog】
http://tomcky.hatenadiary.jp/entry/2014/06/16/224904


いまいち状況がわからないのですが、配列でもそれぞれの要素にUtilities.formatDateを使うことができますよ。

var res = {}, i, l, tmp, key;
var test2 = [ new Date( '2016/05/11' ), new Date( '2016/05/14' ), new Date( '2016/05/15' ) ];
var test3 = [ '2016/05/11 エラー', '2016/05/14 エラー', '2016/05/14 A', '2016/05/15 B' ];

for( i = 0, l = test2.length; i < l ; i++ ) {
    res[ Utilities.formatDate( test2[ i ], 'Asia/Tokyo', 'yyyy/MM/dd' ) ] = [];
}
for( i = 0, l = test3.length; i < l ; i++ ) {
    tmp = test3[ i ];
    for ( key in res ) {
        if ( !res.hasOwnProperty( key ) || tmp.indexOf( key ) == -1 ) { continue; }
        res[ key ].push( tmp );
    }
}
console.dir( res ); // ブラウザのデベロッパーツールで確認する場合

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/05/24 17:27

    ありがとうございます。
    教えていただいたものを理解出来るよう、もう少し調べてみたいと思います。

    キャンセル

  • 2017/05/27 01:31 編集

    ・どうしてもわからない箇所があり、よければ質問させてください
    for in辺りからうまく理解できないでいます。
    tmp.indexOf( key ) == -1では、-1が返ることを利用しているのだと思うのですが、!res.hasOwnProperty( key )がどんなことをしており、なぜ必要なのかがわからず悩んでいます。
    resがkeyというプロパティを含むか?だと思うのですがfor inの箇所でresのプロパティがkeyとして取り出されていっているのだと認識していて、それならば必ず含んでいるのではないかと解釈してしまいます。
    一つづつ試してみたのですが、躓いてしまっています。

    ・例にあげた値について
    例にあげたものがよくありませんでした。申し訳ありません。
    実際のtest3のデータはtest2から抽出し、セルにセットしたものでした。
    その時点までは文字列として扱えたのですが、今回のように拾うと日付型になってしまうのです。例[Thu May 11 00:00:00 GMT+09:00 2017]
    Utilities.formatDateで一つ一つなら扱えるのですが配列では出来ず、その後に何か処理をすることも出来ません。

    キャンセル

  • 2017/06/09 17:11

    たとえば hasOwnProperty などについては、MDN の情報を参照してみると、内容がわかると思います
    その他の項目についても、調べてみてください

    * [Object.prototype.hasOwnProperty() - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty)

    キャンセル

  • 2017/06/12 17:09 編集

    hasOwnPropertyについて少し理解できた気がします。
    ただ配列の番号ではなく、プロパティ名を指定していく方法がわからないでいます。 for(x in res)などを使うのだろうかと思ったので頑張ってみます。
    皆さんありがとうございました。

    キャンセル

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

  • ただいまの回答率 89.13%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる