AppSript 中的动态分组
Dynamic grouping in AppSript
我有一个 Spreadsheet,其中包含大约 3000 行,这些行按订单号分组。我正在尝试构建一个宏来:
删除所有组
对所有行进行多重排序
重新创建组
折叠所有标记为已完成订单的组(可选 - 不知道如何实现)
SHEET_NAME = "PLAN";
SORT_DATA_RANGE = "A2:CJ";
GROUP_DATA_RANGE = "BQ2:BQ";
SORT_ORDER = [
{column: 40, ascending: false},
{column: 2, ascending: true},
{column: 4, ascending: true}
];
function Sortowanie() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
removeAllGroups();
multiSortColumns();
groupRows();
ss.toast('Zakończono.');
}
function multiSortColumns(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(SHEET_NAME);
var range = sheet.getRange(SORT_DATA_RANGE + sheet.getLastRow());
range.sort(SORT_ORDER);
ss.toast('Sortowanie zakończone.');
}
function removeAllGroups() {
const ss = SpreadsheetApp.getActive();
const ssId = ss.getId();
const sheet = ss.getSheetByName(SHEET_NAME);
const sheetId = sheet.getSheetId();
sheet.expandAllRowGroups();
const n = Sheets.Spreadsheets.get(ssId, { ranges: [SHEET_NAME] }).sheets[0].rowGroups.reduce((n, { depth }) => n < depth ? depth : n, 0);
const requests = Array(n).fill("").map(_ => ({ deleteDimensionGroup: { range: { sheetId, dimension: "ROWS" } } }));
Sheets.Spreadsheets.batchUpdate({ requests }, ssId);
ss.toast('Usuwanie grup zakończone.');
}
function groupRows() {
const ss = SpreadsheetApp.getActive();
const sheet = ss.getSheetByName(SHEET_NAME);
const levels = sheet.getRange(GROUP_DATA_RANGE + getLastRowSpecial()).getValues();
const sheetId = sheet.getSheetId();
const requests = levels.flatMap(([a], i) => Array(a).fill("").map(_ => ({ addDimensionGroup: { range: { sheetId, startIndex: i + 1, endIndex: i + 2, dimension: "ROWS" } } })));
Sheets.Spreadsheets.batchUpdate({ requests }, ss.getId());
ss.toast('Ponowne grupowanie zakończone.');
}
function getLastRowSpecial() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const sheet = ss.getSheetByName(SHEET_NAME);
const lastRow = sheet.getRange(GROUP_DATA_RANGE).getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow();
return lastRow
};
当我将范围限制在 1000 行时一切正常。当我尝试 运行 整个范围或超过 1000 个范围并进行调试时,我得到这个:
HttpResponseException: Response Code: 413. Message: response too large.
一段时间后没有调试器我得到这个:
The JavaScript runtime has unexpectedly terminated.
最奇怪的是脚本正在为整个范围创建这些组,然后在一段时间后出现错误。
我认为 3K 行不是一个很大的范围,也许有人知道哪里出了问题?
这是样本数据sheet:
https://docs.google.com/spreadsheets/d/1DLXxZVyrhDxrBe1AX3iy54nQTFVJkoIpeos7M9mEaIo/edit?usp=sharing
你们中的一个问题但可能不是唯一的问题
像这样指定的范围在最后一行和最大行之间生成大量空值
"BQ2:BQ"
尝试像这样重写它们:
"BQ2:BQ" + sheet.getLastRow()
问题:
如果我理解正确的话:
- 您可以删除现有组并根据要创建的组对行进行排序。
- 组由带有
0s
和 1s
的列定义,因此 0
指的是组 header 并且连续的 1s
应该是归为同一组。
- 我在这里假设,在 header 列(第一行)之后,您列中的所有值都是
0
或 1
。
解决方案:
代码示例:
const FIRST_ROW = 2;
function groupRows() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName(SHEET_NAME);
const levels = sheet.getRange(GROUP_DATA_RANGE + getLastRowSpecial()).getValues().flat();
const sheetId = sheet.getSheetId();
const requests = [];
let currentHeader = FIRST_ROW;
while (currentHeader < levels.length) {
let groupLength = levels.slice(currentHeader-FIRST_ROW+1).findIndex(l => l !== 1);
if (groupLength < 0) groupLength = levels.length - currentHeader + 1;
const nextHeader = groupLength + currentHeader+1;
const request = { addDimensionGroup: { range: { sheetId, startIndex: currentHeader, endIndex: nextHeader-1, dimension: "ROWS" } } };
requests.push(request);
currentHeader = nextHeader;
}
Sheets.Spreadsheets.batchUpdate({ requests }, ss.getId());
ss.toast('Ponowne grupowanie zakończone.');
}
注:
此处未显示您的其他功能,但您应该使用它们来删除现有行并确保您的数据根据您的喜好排序。
我有一个 Spreadsheet,其中包含大约 3000 行,这些行按订单号分组。我正在尝试构建一个宏来:
删除所有组
对所有行进行多重排序
重新创建组
折叠所有标记为已完成订单的组(可选 - 不知道如何实现)
SHEET_NAME = "PLAN"; SORT_DATA_RANGE = "A2:CJ"; GROUP_DATA_RANGE = "BQ2:BQ"; SORT_ORDER = [ {column: 40, ascending: false}, {column: 2, ascending: true}, {column: 4, ascending: true} ]; function Sortowanie() { var ss = SpreadsheetApp.getActiveSpreadsheet(); removeAllGroups(); multiSortColumns(); groupRows(); ss.toast('Zakończono.'); } function multiSortColumns(){ var ss = SpreadsheetApp.getActiveSpreadsheet(); var sheet = ss.getSheetByName(SHEET_NAME); var range = sheet.getRange(SORT_DATA_RANGE + sheet.getLastRow()); range.sort(SORT_ORDER); ss.toast('Sortowanie zakończone.'); } function removeAllGroups() { const ss = SpreadsheetApp.getActive(); const ssId = ss.getId(); const sheet = ss.getSheetByName(SHEET_NAME); const sheetId = sheet.getSheetId(); sheet.expandAllRowGroups(); const n = Sheets.Spreadsheets.get(ssId, { ranges: [SHEET_NAME] }).sheets[0].rowGroups.reduce((n, { depth }) => n < depth ? depth : n, 0); const requests = Array(n).fill("").map(_ => ({ deleteDimensionGroup: { range: { sheetId, dimension: "ROWS" } } })); Sheets.Spreadsheets.batchUpdate({ requests }, ssId); ss.toast('Usuwanie grup zakończone.'); } function groupRows() { const ss = SpreadsheetApp.getActive(); const sheet = ss.getSheetByName(SHEET_NAME); const levels = sheet.getRange(GROUP_DATA_RANGE + getLastRowSpecial()).getValues(); const sheetId = sheet.getSheetId(); const requests = levels.flatMap(([a], i) => Array(a).fill("").map(_ => ({ addDimensionGroup: { range: { sheetId, startIndex: i + 1, endIndex: i + 2, dimension: "ROWS" } } }))); Sheets.Spreadsheets.batchUpdate({ requests }, ss.getId()); ss.toast('Ponowne grupowanie zakończone.'); } function getLastRowSpecial() { const ss = SpreadsheetApp.getActiveSpreadsheet() const sheet = ss.getSheetByName(SHEET_NAME); const lastRow = sheet.getRange(GROUP_DATA_RANGE).getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow(); return lastRow };
当我将范围限制在 1000 行时一切正常。当我尝试 运行 整个范围或超过 1000 个范围并进行调试时,我得到这个:
HttpResponseException: Response Code: 413. Message: response too large.
一段时间后没有调试器我得到这个:
The JavaScript runtime has unexpectedly terminated.
最奇怪的是脚本正在为整个范围创建这些组,然后在一段时间后出现错误。
我认为 3K 行不是一个很大的范围,也许有人知道哪里出了问题?
这是样本数据sheet: https://docs.google.com/spreadsheets/d/1DLXxZVyrhDxrBe1AX3iy54nQTFVJkoIpeos7M9mEaIo/edit?usp=sharing
你们中的一个问题但可能不是唯一的问题
像这样指定的范围在最后一行和最大行之间生成大量空值
"BQ2:BQ"
尝试像这样重写它们:
"BQ2:BQ" + sheet.getLastRow()
问题:
如果我理解正确的话:
- 您可以删除现有组并根据要创建的组对行进行排序。
- 组由带有
0s
和1s
的列定义,因此0
指的是组 header 并且连续的1s
应该是归为同一组。 - 我在这里假设,在 header 列(第一行)之后,您列中的所有值都是
0
或1
。
解决方案:
代码示例:
const FIRST_ROW = 2;
function groupRows() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName(SHEET_NAME);
const levels = sheet.getRange(GROUP_DATA_RANGE + getLastRowSpecial()).getValues().flat();
const sheetId = sheet.getSheetId();
const requests = [];
let currentHeader = FIRST_ROW;
while (currentHeader < levels.length) {
let groupLength = levels.slice(currentHeader-FIRST_ROW+1).findIndex(l => l !== 1);
if (groupLength < 0) groupLength = levels.length - currentHeader + 1;
const nextHeader = groupLength + currentHeader+1;
const request = { addDimensionGroup: { range: { sheetId, startIndex: currentHeader, endIndex: nextHeader-1, dimension: "ROWS" } } };
requests.push(request);
currentHeader = nextHeader;
}
Sheets.Spreadsheets.batchUpdate({ requests }, ss.getId());
ss.toast('Ponowne grupowanie zakończone.');
}
注:
此处未显示您的其他功能,但您应该使用它们来删除现有行并确保您的数据根据您的喜好排序。