Remove all grouped rows / columns in a spreadsheet

岁酱吖の 提交于 2021-02-08 08:54:29

问题


I have a Google Sheet that does dynamic grouping with a script. I am looking for a function that gets rid of all those Groups in the sheet again.

Similar to expandAllColumnGroups, I would like to have a function called removeAllColumnGroups - but it seems there is no such function available.

My current approach is very slow and cumbersome. I did quite some research but could not even find a way to get all the columnGroups or at least the start-column-IDs in a sheet, so I iterate over every column and literally try to remove the group if there is one, as there is no way to tell if a group exits. Unfortunately for about 90 columns this takes ages (minutes, really)...

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sh = ss.getActiveSheet();

  //remove all column-groups
  var group = null;
  var maxCol = sh.getMaxColumns();
  for(var c = 1; c <= maxCol; c++) {
    try {
      group = sh.getColumnGroup(c, 1); // Try to get group
      group.remove(); // Remove the group
    } catch (e) {
      //Logger.log("No Group at ColIndex "+c);
    }
  }

Any ideas would be really appreciated. Thanks in advance!


回答1:


Expanding on my comment re: use of the Google Sheets REST API to access and modify row/column groupings:

Row/Column groups are metadata associated with a Sheet resource, and as such can be obtained for all sheets in a workbook with a single HTTP request to spreadsheets.get, with the appropriate fields specification:

GET https://sheets.googleapis.com/v4/spreadsheets/{YOUR_SPREADSHEET_ID}?fields=sheets(columnGroups%2Cproperties(sheetId%2Ctitle)%2CrowGroups)&key={YOUR_API_KEY}

Demo link

The above request returns an object with a sheets property, which is an array of objects (1 per sheet in the spreadsheet) having 3 properties: rowGroups, columnGroups, and properties. The group properties are arrays of DimensionGroup objects, while the properties object contains the sheet's gridId/sheetId, which you need for identifying the sheet in various API requests, and its name (which may be useful for your own script logic).

To delete every row/column group, you need to issue as many DeleteDimensionGroupRequests to do so as the maximum depth returned in your query's groups. If you do not specify the indices of the DimensionRange in your request, this is interpreted as the whole range of the spreadsheet (all rows / all columns, depending on direction).

An example request (requires OAuth authentication, not just API key):

POST https://sheets.googleapis.com/v4/spreadsheets/{YOUR SPREADSHEET ID}:batchUpdate?fields=replies%2FdeleteDimensionGroup

{
  "requests": [
    {
      "deleteDimensionGroup": {
        "range": {
          "sheetId": "{SHEET 1 ID}",
          "dimension": "COLUMNS"
        }
      }
    },
    {
      "deleteDimensionGroup": {
        "range": {
          "sheetId": "{SHEET 2 ID}"
          "dimension": "COLUMNS",
        }
      }
    },
    ...
  ]
}

Demo link

Each delete request has a reply response, and that response will be very similar to the initial response you got for the row/column groups from the initial query. If you knew the gridIds beforehand, you could forgo the initial query and use a while loop to keep sending delete requests while the response contains a dimension group.


To use these methods with Google Apps Script, you can either use UrlFetchApp with raw URL resources, or take advantage of the available "advanced service" client library Sheets (which must first be enabled). Both methods require you to enable use of the Sheets API from your script's Google Cloud Platform project page.

An example using the enabled client library Sheets:

function removeAllGroups() {
  const wb = SpreadsheetApp.getActive(),
        wbId = wb.getId();
  const initial = Sheets.Spreadsheets.get(wbId, {
    fields: "sheets(columnGroups,properties(sheetId,title),rowGroups)"
  });

  // Determine the maximum depth of row & column groups on each sheet in the workbook.
  const maxDepths = {row: {}, col: {}};
  initial.sheets.forEach(function (s) {
    // if (s.properties.title ... (could write logic to do this only for certain sheets)
    var sId = s.properties.sheetId;
    if (s.columnGroups && s.columnGroups.length)
      maxDepths.col[sId] = s.columnGroups.reduce(dgMaxDepth_, 0);
    if (s.rowGroups && s.rowGroups.length)
      maxDepths.row[sId] = s.rowGroups.reduce(dgMaxDepth_, 0);
  });

  // Add all delete requests to an array
  const rqs = [];
  for (var rqType in maxDepths) {
    for (var sheetId in maxDepths[rqType]) {
      addDeleteDGRequests_(rqs, rqType, sheetId, maxDepths[rqType][sheetId]);
    }
  }

  // Send all requests.
  if (rqs.length) {
    const replies = Sheets.Spreadsheets.batchUpdate({requests: rqs}, wbId);
    console.log({message: "Batch response", response: replies});
  }
}

// Callback for Array#reduce
function dgMaxDepth_(val, dg, i, allDGs) {
  return Math.max(val, dg.depth);
}

function addDeleteDGRequests_(requests, rqType, sheetId, num) {
  const dim = rqType === "col" ? "COLUMNS" : "ROWS";
  while (num > 0) {
    var rq = {
      deleteDimensionGroup: {
        range: { sheetId: sheetId,
                 dimension: dim }
      }
    };
    requests.push(rq);
    --num;
  }
}

Resources:

  • Google APIs Explorer - Sheets API
  • Google Sheets REST API
  • Enable Advanced Services
  • Array#reduce
  • Array#forEach


来源:https://stackoverflow.com/questions/52480395/remove-all-grouped-rows-columns-in-a-spreadsheet

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!