こんにちは、イカPOです。
スプレッドシートの1行目をヘッダーとして使っている方は多いと思います。データを扱う際も、ヘッダーを基準にするとコードが読みやすく、後から見直す時にも非常に便利です。
今回は、GASでヘッダーを取得してマッピングを作成し、データを効率よく処理してスプレッドシートに書き込む方法についてご紹介します。
「マッピング」とは?
「マッピング」とは、スプレッドシートのヘッダー名とその位置(インデックス)を紐づける作業のことです。例えば、「在庫数」という列が何列目にあるかを数字ではなく名前で指定できるようになるため、コードが非常に分かりやすくなります。
マッピングの一例
{ “商品ID”: 0, “商品名”: 1, “在庫数”: 2 }
このオブジェクトでは、たとえば「商品ID」というキーを指定すると数字の0が返されます。
返ってきた数値(0)をインデックスとして利用することで、配列の0番目の要素へアクセスできる仕組みになっています。
この仕組みを利用すると、スプレッドシートからデータを取得し、それを加工・書き込みする一連の処理をスムーズに実行できます。
スプレッドシートを操作する流れとサンプルコード
コード全文
function processSheetDataFlow(){
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('データ');
const data = sheet.getDataRange().getValues(); //2次元配列で取得
const headers = data.shift(); // ヘッダー行を取り出す
const headerMap = {};
headers.forEach(function(header, index) {
headerMap[header] = index; // 0始まりのインデックスを設定
});
for (let i =0; i < data.length; i++ ){
Logger.log(`計算前${data[i]}`);
const currentStock = parseInt(data[i][headerMap["在庫数"]],10) || 0;
data[i][headerMap["在庫数"]] = currentStock *2;
}
const updateHeaderMap = {};
headers.forEach(function(header,index){
updateHeaderMap[header] = index + 1;
});
// sheet.getRange(2,1,data.length,data[0].length).setValues(data);
for (let i = 0; i < data.length; i++) {
const targetRow = i + 2; // シートは1始まりなので、2行目から書き込む
sheet.getRange(targetRow, updateHeaderMap["在庫数"]).setValue(data[i][headerMap["在庫数"]]);
}
}
サンプルデータ
商品ID | 商品名 | 在庫数 |
1001 | シャンプー | 4 |
1002 | リンスー | 12 |
1003 | ボディーソープ | 20 |
1004 | コンディショナー | 16 |
1 スプレッドシートからデータを取得
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('データ');
const data = sheet.getDataRange().getValues(); // 2次元配列で取得
const headers = data.shift(); // ヘッダーを取り出す
取得データ(イメージ)
[
["商品ID", "商品名", "在庫数"], // ヘッダー
[1001, "シャンプー", 4],
[1002, "リンスー", 12],
[1003, "ボディーソープ", 20],
[1004, "コンディショナー", 16]
]
2 ヘッダーを取得してマッピングする
ヘッダーを取得したあと、forEachを使ってマッピングを作成します。forEachの構文には配列の要素(header)と、その順番(index)が含まれているので、それを利用してマッピングを行います。
const headerMap = {};
headers.forEach((header, index) => {
headerMap[header] = index; // 配列の順番(0始まり)を取得
});
このマッピングにより、列番号ではなくヘッダー名でデータを扱えるようになります。
3 配列データの加工
配列からデータを取り出し、在庫数を2倍にする処理を行います。
for (let i = 0; i < data.length; i++) {
const currentStock = parseInt(data[i][headerMap["在庫数"]], 10) || 0;
data[i][headerMap["在庫数"]] = currentStock * 2;
}
ここでポイントになるのが、「ヘッダーのマッピング」です。
ヘッダーのマッピングについて
マッピングとは、ヘッダーの項目名と、その項目が配列の何番目(インデックス)に位置しているかを紐付ける作業のことを言います。
スプレッドシートから取得したデータは、以下のようになっています。
[
["商品ID", "商品名", "在庫数"], // ヘッダー
[1001, "シャンプー", 4], // データ1行目
[1002, "リンスー", 12], // データ2行目
]
ここからヘッダーを取り出して、マッピングを行います。
const headers = data.shift(); // ["商品ID", "商品名", "在庫数"]
const headerMap = {};
headers.forEach((header, index) => {
headerMap[header] = index;
});
ここで使ったforEachは、配列の各要素を順番に取り出すためのJavaScriptのメソッドで、自動的にその要素の順番(インデックス)を取得することができます。
• “商品ID” は0番目(indexが0)
• “商品名” は1番目(indexが1)
• “在庫数” は2番目(indexが2)
これにより、以下のようなマッピングが出来上がります。
{ “商品ID”: 0, “商品名”: 1, “在庫数”: 2 }
このマッピングを使うことで、データの取得や書き込みを、配列の番号(インデックス)ではなく、ヘッダー名を使って行うことができます。
例えば、
data[i][headerMap[“在庫数”]]
という記述は、
data[i][2]
と記述するのと同じ意味になります。
つまり、「在庫数」と指定すると、マッピングによって「2」という数字が取得され、その結果、配列内の「在庫数」に該当するデータにアクセスできるという仕組みです。
この仕組みを踏まえ、改めて在庫数を2倍にする処理を見てみましょう。
for (let i = 0; i < data.length; i++) {
const currentStock = data[i][headerMap["在庫数"]];
data[i][headerMap["在庫数"]] = currentStock * 2;
}
こうすることで、配列内の「在庫数」に該当するデータが更新されます。
4 書き込み用のマッピング(1始まり)
スプレッドシートへの書き込み時は、シートが1始まりのため、ヘッダーのインデックスに+1をしてマッピングします。
const updateHeaderMap = {};
headers.forEach((header, index) => {
updateHeaderMap[header] = index + 1;
});
スプレッドシートに書き戻すときは、作成した1始まりのマッピングを使って書き込みます。
5 スプレッドシートにデータを書き込む(在庫数の更新)
変更後のデータをシートに反映する方法です。
ここでのポイントは、行番号と列番号がシート上では1始まりであるため、配列(0始まり)とのズレを調整することです。
for (let i = 0; i < data.length; i++) {
const targetRow = i + 2; // シートは1始まりなので、2行目から書き込む
sheet.getRange(targetRow, updateHeaderMap["在庫数"]).setValue(data[i][headerMap["在庫数"]]);
}
行番号の調整:i + 2
の部分は、配列のインデックス i
(0始まり)を、スプレッドシートの行番号(1始まり)に合わせるための工夫です。
i = 0
→ シート上は2行目i = 1
→ シート上は3行目
といった形で対応させています。
列番号の指定:updateHeaderMap["在庫数"]
で取得されるのは、書き込み用に「1始まり」に変換した列番号です。headerMap["在庫数"]
は配列上で在庫数が何番目かを示す「0始まり」のインデックスです。
書き込むデータを持ってくる「列番号」は headerMap
書き込み先の「列番号」は updateHeaderMap
別の書き込み方法
以下のように一括書き込みも可能です。
sheet.getRange(2, 1, data.length, data[0].length).setValues(data);
まとめ
流れのイメージは以下の通りです。
- データ取得(0始まり)
- ヘッダーマッピング作成(0始まり)
- 配列上でデータ処理(0始まり)
- 書き込み用マッピング作成(1始まり)
- シートへの書き込み(1始まり)
✅ 配列処理は0始まりのまま行う
✅ シートに書き込むときは1始まりで扱う
このパターンを覚えるだけで、GASのコードが劇的にわかりやすくなります。ぜひ試してみてください!
この記事についてのご意見や間違いのご指摘は、ぜひX(旧Twitter)でお知らせください!
皆さまのフィードバックをお待ちしています。以下のアカウントまでお気軽にメッセージをお寄せください。
この記事には筆者の個人的な解釈も一部含まれています。一つの参考としてお読みいただきつつ、最終的にはご自身や担当の方としっかり相談の上で判断いただけますと幸いです。
皆様の声で情報をアップデートしていきます。よろしくお願いします。