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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

Q&A

解決済

2回答

1348閲覧

【GAS】getRange().getValues()で取得した値で .some()は使えるか?

donguriko

総合スコア30

Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

1グッド

0クリップ

投稿2022/12/09 14:15

編集2022/12/09 14:19

前提

スプレッドシート上の表1、表2二つのデータがあります。
下記「実現したいこと」に記載した処理をGASで行いたいです。
どのようなコードをかけば実現できるかアドバイスが欲しいです。

表1、表2のイメージ
イメージ説明
※上記イメージでは12/5は表1に記載なしですが12/5も表1に記載が
あるものとみなしてください。

実現したいこと

<最終形>
1)表2の各値が表1に含まれているかチェック
2)含まれている場合は、表2のG列に「休」フラグを立てたい

試したこと

<考えたこと>
.some( )を使えば、含まれていればtrue、なければfalseが
戻せるようなので、if(戻り値 === true)なら、
{G列に.setValue("休み") }とすればできるのでは?

<やってみたこと>
そもそも .some( )の使い方がよくわからないので、
まずは下リンク先の「アロー関数を使ったある値が存在するか
どうかのチェック」の例を少しずつ変化させながら、
「やりたいこと」に近づけられないか? と試みました。
⇒ 参照したサイト

<変化させて躓いたところ>
値bananaが含まれているかを確認する先の配列データを
getRange().getValues()で表3からまるっと取得し、
配列fruitsに push() する記載にコードを変えたところ、
falseが戻ってきてしまいうまくいきませんでした。
(値bananaはコード上で直接指定のまま)

NGverコード
イメージ説明

(参考) OKver_オリジナルコード
イメージ説明

<教えてほしいこと>
①getRange().getValues()で取得した値で .some()は使えないのですか?

②半ば丸投げになってしまい申し訳ありませんが、
どのようなアプローチをすればGASで<最終形>が実現できますか?

該当のソースコード

OK(オリジナルver)、NGver両方記載します。

GAS

1★ OKver ★ 2function myFunction1() { 3const fruits = ['apple', 'banana', 'mango', 'guava']; 4 5function checkAvailability(arr, val) { 6 7 return arr.some((arrVal) => val === arrVal); 8} 9 10//const chk1 = checkAvailability(fruits, 'kela'); 11//console.log(chk1); //falseが出た 12 13const chk2 =checkAvailability(fruits, 'banana'); 14console.log(chk2); //trueが出た 15} 16 17 18★ NGver ★ 19function myFunction2() { 20const ss = SpreadsheetApp.getActiveSpreadsheet(); 21const sheet = ss.getActiveSheet(); 22 23const fruits = []; 24const myValue = sheet.getRange(4,9,4,1).getValues(); 25fruits.push(myValue); 26console.log("fruits " +fruits); 27 28function checkAvailability(arr, val) { 29 30 return arr.some((arrVal) => val === arrVal); 31} 32 33const chk2 =checkAvailability(fruits, 'banana'); 34console.log(chk2); 35} 36

補足情報(FW/ツールのバージョンなど)

アロー関数、コールバック関数等について理解がまだ不十分です。
少しでも、自分でできるようになりたいので、お手数をおかけして
大変申し訳ありませんが、非エンジニアビギナーでも理解できる
レベルのかみ砕いたアドバイス、解説をいただけると助かります。

Cocode👏を押しています

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

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

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

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

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

guest

回答2

0

ベストアンサー

①getRange().getValues()で取得した値で .some()は使えないのですか?

使えますが、質問の場合、下記のようにする必要があります(先に答えを示して、その後で解説します)
削除・修正したところはコメントアウトしています。

js

1function myFunction2() { 2 const ss = SpreadsheetApp.getActiveSpreadsheet(); 3 const sheet = ss.getActiveSheet(); 4 5 //const fruits = []; // 削除 6 //const myValue = sheet.getRange(4, 9, 4, 1).getValues(); 7 const fruits = sheet.getRange(4, 9, 4, 1).getValues().flat(); // 修正 8 9 //fruits.push(myValue); 10 //console.log("fruits " + fruits); 11 console.log(fruits); // 修正 12 function checkAvailability(arr, val) { 13 return arr.some((arrVal) => val === arrVal); 14 } 15 16 const chk2 = checkAvailability(fruits, "banana"); 17 console.log(chk2); 18}

ポイント1.getValues() で取得したデータの形を正しく確認する方法。
→ 配列の形を確認する場合は、GASではconsole.log の中で+記号等で文字列連結しない。

まず、OKバージョンとNGバージョンで出力結果が同じであるにもかかわらず、NGでは期待した結果が得られなかったのが、そもそもの疑問点であると理解しました。この点について説明します。

元の質問文では、

js

1console.log("fruits " + fruits);

というように、console.log の中で 'fruits' という文字列と、配列 fruits が連結されています。
しかし、console.log で 文字列と配列を+記号で連結してしまうと、配列の正しい形を確認することができません。

具体的に言うと、 fruitsは、
[[['apple'], ['banana'], ['mango'], ['guava']]]
のような形(配列の中に配列が入れ子になった3重の配列)になっていますが、
他の文字列と配列を+記号で連結して

js

1console.log("fruits" + fruits);

としてしまうと、表示上は入れ子が外れて、質問内の画像にあるように

fruits apple, banana, mango, guava

と表示されてしまいます。
(ただしこれはあくまで表示だけで、内部の配列の構造が変わっているわけではありません。またこのようになるのは、現時点のGASエディタ特有の現象であり、他の処理系では必ずしも同様になるとは限りません)

ここは、

js

1console.log(fruits);

のように、console.log関数の括弧の中に形を確認したい変数だけ入れることで、

[ [ ['apple'], ['banana'], ['mango'], ['guava'] ] ]

とそのままの形で出力されます。

または、出力したい文字列・項目をカンマで区切って指定することでも同じようにそのまま出力できます。

js

1const x = [['apple'], ['banana'], ['mango'], ['guava']]; 2const y = []; 3y.push(x); 4console.log('x=', x, '\n', 'y=', y); //'\n'は改行 5 6出力結果 7>> x= [ ['apple'], ['banana'], ['mango'], ['guava'] ] 8>> y= [ [ ['apple'], ['banana'], ['mango'], ['guava'] ] ]

※誤解しないでいただきたいのですが、console.log の中で+記号で文字列連結をすること自体は特に間違いではありません。
ただ、現時点のGASエディタでは、console.log()を用いて配列の形を確認する際に+記号で連結すると、実際の配列の構造と異なる形で表示されてしまうという点に注意してほしい、ということです。

 
ポイント2.someで比較している対象
下記は、元のNGバージョンのコードで
console.log('fruits'+fruits);を
console.log(fruits);に直しただけのコードです。(途中まで)

js

1function myFunction2() { 2 const ss = SpreadsheetApp.getActiveSpreadsheet(); 3 const sheet = ss.getActiveSheet(); 4 const fruits = []; 5 const myValue = sheet.getRange(4, 9, 4, 1).getValues(); 6 7 fruits.push(myValue); 8 console.log(fruits); // 修正

これを実行すると、

[[['apple'], ['banana'], ['mango'], ['guava']]]

と表示されます。

このfruits に対して、some を適用しても、期待通りの結果になりません。
なぜなら、
getgValues() で得た myValue の内容は [['apple'], ['banana'], ['mango'], ['guava']]となっていて
fruits はさらに []の中に myValueをpushしたものになっているからです(3重の入れ子)

js

1function myFunction2() { 2 const ss = SpreadsheetApp.getActiveSpreadsheet(); 3 const sheet = ss.getActiveSheet(); 4 const fruits = []; 5 const myValue = sheet.getRange(4,9,4,1).getValues(); 6 fruits.push(myValue); 7 function checkAvailability(arr, val) { 8 return arr.some((arrVal) => val === arrVal); 9 } 10 const chk2 =checkAvailability(fruits, 'banana'); 11 console.log(chk2); 12}

上はNGバージョンと同じコードですが、上のコードを実行した場合、 checkAvailability のarr には
myValue すなわち

[[['apple'], ['banana'], ['mango'], ['guava']]]

という3重の入れ子になった配列が渡され、

js

1 arr.some((arrVal) => val === arrVal);

の arrVal という引数には、

[[['apple'], ['banana'], ['mango'], ['guava']]]

の1つ内側の要素

[['apple'], ['banana'], ['mango'], ['guava']]

が渡されることになります。

結果
[['apple'], ['banana'], ['mango'], ['guava']]'banana' が等しいかどうかを1回だけ比較することになってしまい、これはfalse(等しくない)となります。

ポイント3.flat() 関数

ポイント2で、 getValues で得た myValue (fruitsにpushする前)は
[['apple'], ['banana'], ['mango'], ['guava']]
という形になっていますが、これを checkAvailability に渡しても
['apple'], ['banana'], ['mango'], ['guava'] というそれぞれの要素を 'banana'という文字と比較することになってしまい
すべて等しくない(false) となってしまいます。

本件で
arr.some((arrVal) => val === arrVal);
のところで期待するように some を動作させるには、
arr が1重の配列となっている必要があります。

「1重の配列」とは
[['apple'], ['banana'], ['mango'], ['guava']]
ではなく
['apple', 'banana', 'mango', 'guava']
の形です。

各要素から [ ] を取り外すには、flat() という関数を使います。

js

1const a = [['apple'], ['banana'], ['mango'], ['guava']]; 2const b = a.flat(); 3console.log(b); 4 5>>> ['apple', 'banana', 'mango', 'guava']

投稿2022/12/10 00:17

編集2022/12/10 01:47
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

0

①getRange().getValues()で取得した値で .some()は使えないのですか?

使えますが、そのままでは使えません。

②半ば丸投げになってしまい申し訳ありませんが、どのようなアプローチをすればGASで<最終形>が実現できますか?

  • .flat()を使用しましょう。
  • また.some()を使用する意味は今回はありませんので、.includes()を推奨します。

不具合の原因と対策

イメージ説明

.getValues()で取得できる配列は「2次元配列」です。
例を見てみましょう。
A2〜A4の値を取得してきて、そこに「apple」が含まれているかどうかを判別したいとします。

  • .getValues()で取得してきた配列originalValuesは[ [ 'apple' ], [ 'banana' ], [ 'orange' ], [ 'kiwi' ] ]という2次元配列です。
  • originalValuesに'apple'が含まれているか?というと含まれていません。
    • ['apple']はありますが、'apple'は存在しません。
    • ですのでfalseとなります(originalResult参照)。
  • では['apple']は含まれているか?と.some()を使ってみてもfalseになります(originalResult2参照)。
    • JavaScriptではたとえ中身が同じ値だとしても、別々に作った配列・オブジェクトは別物ととらえるからです。
  • ではどうすればいいのか?取得してきた配列を.flat()を用いて1次元配列化すればいいのです。
    • [ 'apple', 'banana', 'orange', 'kiwi' ]という形にすれば、.some()の検索にもちゃんとひっかかってくれますね(newResult参照)。

javascript

1function someTest() { 2 const sheet = SpreadsheetApp.getActiveSheet(); 3 const originalValues = sheet.getRange(2, 1, 4, 1).getValues(); 4 5 console.log(originalValues); 6 // [ [ 'apple' ], [ 'banana' ], [ 'orange' ], [ 'kiwi' ] ] 7 8 const originalResut = originalValues.some(val => val === 'apple'); 9 console.log(originalResut); // false 10 const originalResut2 = originalValues.some(val => val === ['apple']); 11 console.log(originalResut2); // false 12 13 const newValues = originalValues.flat(); 14 console.log(newValues); 15 // [ 'apple', 'banana', 'orange', 'kiwi' ] 16 17 const newResult = newValues.some(val => val === 'apple'); 18 console.log(newResult); // true 19}

正解コード例

ただの値を検索するだけであれば.some()をわざわざ使う必要性はなく、.includes()を用いればいいと思います。
配列の中に指定の値が含まれればtrue、含まれないならfalseを戻してくれます。

例で、Needleの値がHaystackに含まれていれば✅を入力するコードを書いてみました。

イメージ説明

javascript

1function searchNeedleInHaystack() { 2 const sheet = SpreadsheetApp.getActiveSheet(); 3 const haystack = sheet.getRange(2, 1, 4, 1).getValues().flat(); 4 // [ 'apple', 'banana', 'orange', 'kiwi' ] 5 const needles = sheet.getRange(2, 3, 3, 1).getValues().flat(); 6 // [ 'apple', 'tomato', 'banana' ] 7 8 const result = needles.map(needle => haystack.includes(needle) ? ['✅'] : ['']); 9 // [ ['✅'], [''], ['✅'] ] 10 sheet.getRange(2, 4, 3, 1).setValues(result); 11}

この部分 haystack.includes(needle) ? ['✅'] : [''] は、三項演算子と呼ばれるif/elseを1行で書ける記法です。
詳細は下記サイトをご覧ください。

蛇足ですが、こういうたくさんの中から1つを見つけるサンプルコードを書く際は、海外の慣習でhaystack(干し草の山)からneedle(針)を探すという表現をしますので、今回サンプルを提示する際にその用語を使わせていただきました。

投稿2022/12/09 17:18

編集2022/12/09 18:10
Cocode

総合スコア2314

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

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

donguriko

2022/12/10 01:27

Cocodeさま 丁寧なレクチャーありがとうございます!! 配列少しわかった気になっていましたが、やっぱり理解がまだ足りなかった、と 改めて気づきました。 getValues()で取得すると、二次元配列になるのですね。。。 一元配列と二次元配列の違いは行×列が1×1ならgetValues()で取得しても一次元、 2×1、1×2、2×2だと二次元だと勘違いしていました。 正しく理解できていないことに気づくことができました。 ありがとうございました。 また、条件演算子のリンクもありがとうございました。 アロー関数、map等は????と教えていただいたMDNリンクを読んでも 内容が上滑りして、すんなり頭に入ってきませんでしたが、この内容は なんとか理解できそうです。 (記載してある「そのまま」はなんとか理解できても、別のケースに置き換え たり、少しひねるとやっぱり自分がわかっていないことに気づく) いただいた回答例を少しずつ変えて、感覚をつかみたいと思います。 お忙しい中、ビギナー向け解説 ありがとうございました。 親切にレクチャーしてくださるので、非エンジニアでもなんとか折れずに こうしてGASの勉強を続けられています。感謝。 回答ありがとうございました。 追伸・・・haystack(干し草の山)からneedle(針)、勉強になりました♪
donguriko

2022/12/10 01:50 編集

qnoirさま お忙しい中、回答ありがとうございます!! ▼ポイント1 まさに 躓いていたところです! cocodeさま回答を写経しながら自分で1つずつ再現して確かめていたところ、 console.log()で確認した時に、 なぜflat()した時と、flat()しなかった時で同じように出てくるのか、 なぜcocodeさまの回答にある[]がconsole.log()で見れないのか? 見えないのにどうして[]の有無がわかるのか、 概念として頭の中でしか見られないのか???、 cocodeさまは別の方法で確認しているのか?? 、 とちょうど「さら問い」をしよう、と思っていたところでした。 console.log()で確認する際、何の結果が出てきているのかわからなくなってしまうので いつも頭に "何をみたいのか "+ として確認していたのですが、配列を確認したい場合は、 このやり方は要注意、勉強になります。 そして、代替策として「カンマで区切ればよい」まで教えていただき感謝です。 次から活用します。 ▼ポイント3 なぜflat()をしているのか、ずっとピンと来ず、モヤモヤしていたところでした。 flat()をすることで[]をはずしていたのですね。霧が晴れた気がします。 qnoirさま解説で「配列」の壁をなんかとよじ登れました。 ここにきて、map()、filter() 等 新しい壁に苦戦中ですが、いつも困った時に 手を差し伸べてくださり感謝しています。 しっかり自分のモノにできるよう頑張ります。 回答ありがとうございました!!
Cocode

2022/12/10 15:50 編集

アロー関数に関しては基本の記法なので、ググってでてきた説明と同じ説明しか私にはできません。 解説をお読みになって自分なりに書いてみて不明点があればお教えください。 そちらの内容を補足解説することは可能です。 .map()の解説はアロー関数が理解できてからですかね。 アロー関数を使わず使用することもできますが、基本的にアロー関数とセットで使いますので!
donguriko

2022/12/12 10:29 編集

Cocodeさま、qnoirさま 先日は、回答ありがとうございました。 自分でやってみたところ、果物・野菜verでは想定どおりの結果を 得ることができました。 次ステップとして、最終形の日付verを試みたのですが、 想定どおりの結果を得ることができません。 すべてfalse判定となってしまいます。 もし初歩の初歩の見落としてでしたら申し訳ありません。 原因と解消法がわからないため、下記で新たな照会をさせていただきました。 https://teratail.com/questions/5c72935a1msqw9 お忙しいところ大変申し訳ありませんが、回答は急ぎませんので お時間がある時でよいので、アドバイス、レクチャーをお願いできます でしょうか? 追伸・・・Cocodeさま、アロー関数ありがとうございます!! まずは、しっくりくるまで手を動かしてみてアロー関数に慣れようと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問