My accounting software exports most recent data into a spreadsheet which contains lot of data that is hard to analyze without grouping it.
I’d like to group rows based on similarity to the row above it (Or potentially based on indent, but that might be more difficult).
For example, there is a Discounts and promotions section which has several sub-items (sometimes an item might get added, so in the xample below, at some random point there could be 4 rows of sub-content vs. 3). At the bottom is the Total for that section.
The total row always has the same exact title with the word "Total " appended to the front.
Discounts & promotions
Discounts & promotions - Facebook (via Shopify)
Discounts & promotions - Shopify - name
Discounts & promotions - Shopify - name - gift card giveaways
Total Discounts & promotions
Here is a link to some sample data.
Is there a script that can go through the whole sheet and group sections by logic – if this row has the same exact content as this other row + the word Total at the front, then group them.
(Also first I need the script to remove all groups – this is working, and last I need the script to collapse all groups,this is also working)
Here is the code I tried. Nothing is happening to the data in the spreadsheet.
function removeAllGroups1() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Daily");
const rg = sh.getDataRange();
const vs = rg.getValues();
vs.forEach((r, i) => {
let d = sh.getRowGroupDepth(i + 1);
if (d >= 1) {
sh.getRowGroup(i + 1, d).remove()
}
});
}
function groupRows() {
const sheet = SpreadsheetApp.getActiveSheet();
const range = sheet.getRange("A1:A" + sheet.getLastRow());
const values = range.getValues();
let previousValue = "";
let groupStartRow = 1;
for (let i = 0; i < values.length; i++) {
const currentValue = values[i][0];
// Check if the current value is a "Total" version of the previous value
if (currentValue.startsWith("Total ") && currentValue.substring(6) === previousValue) {
// Group the current row with the previous row
sheet.getRange(i + 1, 1).shiftRowGroupDepth(1);
} else {
// Reset the group start row
groupStartRow = i + 1;
}
previousValue = currentValue;
}
}
function collapse() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Daily');
let lastRow = sh.getDataRange().getLastRow();
for (let row = 1; row < lastRow; row++) {
let depth = sh.getRowGroupDepth(row);
if (depth < 1) continue;
sh.getRowGroup(row, depth).collapse();
}
}
2
Answers
Use
Array.findIndex()
, like this:See Array.findIndex().
You want to group rows on a P&L based on a "cell value" being followed by a subsequent "Total" cell value. For example, "Sales" and "Total Sales".
Consider this answer.
Logic
removeExistingGroups("Daily")
– delete existing groups; re-uses the OP’s codevar data = dataRange.getValues().flat()
get the values in Column A as a 1D arrayfor (i=0;i<data.length;i++){
– loop through the rowsvar title = data[i]
– get the row valuevar totalTitle = "Total "+title
– create an equivalent "Total" valuevar index = data.indexOf(totalTitle)
– use indexOf to find a match for the "Total value"var groupRange = sheet.getRange(dataRow,1,matchRow-dataRow)
groupRange.shiftRowGroupDepth(1);
– group the rangeSAMPLE – OUTPUT