✨split data into tabs
💾 程式:Google Sheet
// 🔸 app
const app = {};
// 🔸 app.spreadsheet
// const (所以直接存儲在 app 屬性中就好)
app.spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
// 🔸 app.sheets()
app.sheets = function(){
return app.spreadsheet.getSheets()
};
// 🔸 app.sourceSheet()
app.sourceSheet = function(){
return app.sheets()[0]
};
// 🔸 app.sourceSheetName()
app.sourceSheetName = function(){
return app.sourceSheet().getName()
};
// 🔸 unique course names
// 傳回 H 欄的所有科目(去除重複)
app.uniqueCourses = function uniqueCourses(){
return app.sourceSheet()
.getRange("H2:H") // H column
.getValues() // 2D data
.map(row => row[0]) // 每列取第一筆資料 (只有一筆資料)
.unique()
.filter(x => x); // ⭐️ remove empty string
};
// 🔸 app.insertSheetByName(rawName)
// 將分科的資料放到新的頁面中
app.insertSheetByName = function (rawName, {
autoresize = true // resize cols
}={}) {
// tab name
const name = tabName(rawName);
// get worksheet by name
let ws = app.spreadsheet.getSheetByName(name);
// if already exists, quit.
if(ws){
log(`⚠️ 頁面「${name}」已經存在,取消插入試算表。`);
return
};
// source sheet name
const sourceSheetName = app.sourceSheetName();
// 1. create a worksheet
ws = app.spreadsheet.insertSheet();
// 2. rename sheet
// const rawName = "1011010101.國語文"
ws.setName(name);
// 3. set formula to A2 cell
ws.getRange("A2")
.setFormula(`=FILTER(${sourceSheetName}!B2:K,${sourceSheetName}!H2:H="${rawName}")`)
// 4. copy title row from source sheet
app.sourceSheet()
.getRange("B1:L1")
.copyTo(ws.getRange("A1:K1")) // 注意:原始資料從 B 欄開始。
// 5. 調整欄位寬度
if(autoresize) app.resizeColumns(ws);
// 6. 除了「補考成績」欄位外,鎖住其他欄位。
app.protectSheet(ws);
};
// 🔸 protect sheet
// 6. 除了「補考成績」欄位外,鎖住其他欄位。
app.protectSheet = function(sheet){
var protection = sheet.protect(); // protect sheet
protection.setUnprotectedRanges([sheet.getRange("I2:I")]); // unprotect I column
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
};
// 🔸 split data into separate tabs
app.splitIntoTabs = function(){
const courses = app.uniqueCourses();
log(`🚩 開始產生 ${courses.length} 個分頁。`);
courses.forEach( rawName => {
app.insertSheetByName(rawName);
});
log(`🏁 產生 ${courses.length} 個分頁完成。`);
};
// 🔸 delete all sheets execpt source sheet
app.deleleteAllGeneratedSheets = function(){
app.sheets().forEach( sheet => {
const name = sheet.getName();
if(name !== app.sourceSheetName()) {
app.spreadsheet.deleteSheet(sheet);
log(`⚠️ 頁面「${name}」已刪除❗`);
}
})
};
// 🔸 autoresize all columns in `sheet`
// 似乎對中文不管用❓
app.resizeColumns = function(sheet) {
// var sheet = SpreadsheetApp.getActiveSheet();
// var dataRange = sheet.getDataRange();
// var i = dataRange.getColumn(); // first col
// var n = dataRange.getNumColumns(); // number of columns
// sheet.autoResizeColumns(i, n);
sheet.setColumnWidths(1, 6, 60);
sheet.setColumnWidths(7, 1, 200); // 科目
};
// 🔸 「科目」欄位名稱不能簡化,因為有的科目有不同科目代碼,
// 例如:101101040E.生物、105101040E.生物
function tabName(rawValue) {
return rawValue;
// 1. split by "."
// 2. return last part
// return rawValue.split(".")[1]
}
// log(...)
const {log} = Logger;
// ⭐️ array.unique()
Array.prototype.unique = function(){
return [... new Set(this)] // (remove duplicates)
};
// onOpen()
function onOpen() {
var ui = SpreadsheetApp.getUi(); // app UI
// ♥ 自製工具
ui.createMenu('🧰 工具箱')
.addItem('📥 原始報表 ➠ 分科', 'runApp')
.addItem('💾 分科頁面另存新檔', 'tabsToFiles')
.addItem('🗑️ 刪除所有生成頁面❗', 'deleteSheets')
.addToUi();
}
function runApp(){
app.splitIntoTabs();
}
function deleteSheets(){
app.deleleteAllGeneratedSheets();
}
// create file for each tab
function tabsToFiles(){
const sheets = app.sheets();
log(`🚩 開始產生 ${sheets.length} 個檔案。`);
sheets.forEach(sheet => {
// get sheet's data, name
const data = sheet.getDataRange().getValues();
const name = sheet.getName();
// get new file (with sheet name)
// files will be saved to root folder by default.
const file = SpreadsheetApp.create(name);
log(`✨ 產生新檔案:「${name}」。`);
// copy data to new sheet
const sheet2 = file.getSheets()[0];
sheet2.setName(name);
sheet2
.getRange(1, 1, data.length, data[0].length)
.setValues(data);
// protect sheet
app.protectSheet(sheet2);
});
log(`🏁 產生 ${sheets.length} 個檔案完成。`);
}
Shift + Click:選取同一行(列)
Shift + Ctrl + ⬇️:選到最後一行
// 抓出 H 行 = "1011010101.國語文" 的所有資料
// ╭─────── condition ────────╮
// ╭─range─╮ ╭column─╮ ╭──── value ─────╮
=FILTER(Data!B2:K, Data!H2:H="1011010101.國語文")
// ↑ ↑
// ⭐️ 最後一行的「行號」不要打,會節省不少事。
Last updated