Apps Script技术求助:按Country唯一值合并多行数据为指定格式多维数组
问题描述
我有一个Google Sheet,每次更新时行列数都会动态变化,数据如下:
| country | product | type | user |
|---|---|---|---|
| JP | p1 | t1 | u1 |
| JP | p1 | t2 | u2 |
| JP | p1 | t3 | u2 |
| JP | p2 | t2 | u3 |
| HK | p3 | t2 | u1 |
| HK | p1 | t3 | u1 |
| KR | p1 | t2 | u1 |
我需要将数据存入一个数组,以country列的唯一值为分组依据,将其余列的唯一值合并(用/连接),数组的维度由country列的唯一值数量决定,上述示例应为二维数组(注:原描述的“三维数组”应为笔误,实际是二维数组,每个子数组对应一个国家的聚合结果)。
期望输出数组格式如下:[["JP","p1/p2","t1/t2/t3","u1/u2/u3"],["HK","p1/p3","t2/t3","u1"],["KR","p1","t2","u1"]]
目前我只能得到如下格式的数组,无法将同一列的值用/连接:[["JP","p1","p2","t1","t2","t3","u1","u2","u3"],["HK","p1","p3","t2","t3","u1"],["KR","p1","t2","u1"]]
以下是我的代码,请问问题出在哪里?
function testtogetcombine() { var spreadsheet = SpreadsheetApp.getActiveSpreadsheet(); var sheet1 = spreadsheet.getSheetByName("test"); var lastRow = sheet1.getLastRow(); var lastColumn = sheet1.getLastColumn(); var values = sheet1.getRange(1, 1, lastRow, lastColumn).getValues(); var newSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('outcome'); var outLastRow = newSheet.getLastRow(); var counter=1; var orgtitle=["country","product","type","user"] var col_geo=[]; var geo=[]; for (var c=0; c<=orgtitle.length;c++) { for (var j=0;j<=lastColumn-1;j++) { if(values[0][j]==orgtitle[c] ){ col_geo.push(j) } } } for (var i=1;i<lastRow-1;i++) { var duplicate = false; for (n in geo){ if(values[i][col_geo[0]]==geo[n]){ duplicate = true; } } if(!duplicate) { geo.push(values[i][col_geo[0]]) } } var result=new Array(geo.length); for (var j=0;j<result.length;j++){ result[j]=[]; result[j].push(geo[j]) } var temp=[]; for (var j=0;j<result.length;j++){ for (var c=0; c<col_geo.length;c++) { // temp[c]=[]; for (var i=0;i<lastRow;i++){ if (values[i][col_geo[0]] == result[j][0]) { // temp[c].push(values[i][col_geo[c]]); var duplicate = false; for (n in result[j]){ if(values[i][col_geo[c]]==result[j][n]){ duplicate = true; } } if(!duplicate) { result[j].push(values[i][col_geo[c]]); } } // if (values[i][col_geo[0]] == "JP"){ // var duplicate = false; // for (n in temp){ // if(values[i][col_geo[c]]==temp[n]){ // duplicate = true; // } // } // if(!duplicate) { // temp.push(values[i][col_geo[c]]); // Logger.log(temp) // temp=[]; // } } } } Logger.log(result); }
问题分析与解决方案
核心问题
你的代码当前是把每个唯一值逐个追加到result[j]数组中,没有针对每一列单独收集唯一值后再用/拼接:
- 没有为每个国家的每一列(product、type、user)单独维护唯一值集合,而是直接把所有列的唯一值堆到同一个数组里。
- 缺少将同一列的唯一值用
/连接的步骤,导致最终数组是扁平化的多个值,而非拼接后的字符串。 - 原循环
i<lastRow-1会跳过最后一行数据,导致部分信息丢失。
修正后的代码
function testtogetcombine() { const spreadsheet = SpreadsheetApp.getActiveSpreadsheet(); const sheet1 = spreadsheet.getSheetByName("test"); const lastRow = sheet1.getLastRow(); const values = sheet1.getRange(1, 1, lastRow, sheet1.getLastColumn()).getValues(); // 获取表头对应的列索引 const orgtitle = ["country", "product", "type", "user"]; const colIndices = orgtitle.map(title => values[0].indexOf(title)); // 按country分组,用Set自动去重存储各列值 const countryGroups = {}; for (let i = 1; i < lastRow; i++) { const row = values[i]; const country = row[colIndices[0]]; if (!countryGroups[country]) { // 初始化分组:[国家名, product集合, type集合, user集合] countryGroups[country] = [country, new Set(), new Set(), new Set()]; } // 将对应列的值加入Set(自动去重) countryGroups[country][1].add(row[colIndices[1]]); countryGroups[country][2].add(row[colIndices[2]]); countryGroups[country][3].add(row[colIndices[3]]); } // 将Set转为/连接的字符串,生成最终数组 const result = Object.values(countryGroups).map(group => { return [ group[0], [...group[1]].join('/'), [...group[2]].join('/'), [...group[3]].join('/') ]; }); Logger.log(result); }
关键改进点
- 对象分组+Set去重:用
countryGroups对象按国家分组,每个分组内用Set存储对应列的唯一值,Set会自动处理重复值,比手动判断更高效。 - 列维度独立处理:为每个国家的product、type、user列分别维护独立的Set,确保同一列的唯一值被集中收集。
- 字符串拼接:最后将每个Set转为数组,用
join('/')拼接成目标格式的字符串,再组合成最终数组。 - 修复数据遗漏:循环从
i=1到i<lastRow,确保所有数据行都被处理。
内容的提问来源于stack exchange,提问作者keavy
相关产品推荐
相关产品推荐

