如何使用GAS按PO号时间戳从二维数组提取最新条目?
如何提取每个OrderPO对应的最新时间戳行?
问题描述
需要依据表格A列(OrderPO)的时间戳,提取每个PO号对应的最新行(时间戳最晚的行),尝试使用sort()方法实现但未成功,以下是数据集和当前代码,求解决方法。
数据集
| OrderPO | TimeStamp | Unit |
|---|---|---|
| TTL-220218 | 8/17/2022 20:47:55 | |
| TTL-220218 | 8/18/2022 7:49:49 | |
| TTL-220220 | 8/17/2022 18:00:55 | |
| TTL-220220 | 8/18/2022 9:49:49 | |
| TTL-220219 | 8/17/2022 20:47:55 | |
| TTL-220219 | 8/18/2022 7:49:49 | |
| TTL-220219 | 8/17/2022 20:47:59 | |
| TTL-220216 | 8/18/2022 8:30:49 |
当前代码
function getLastestEntries() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getSheetByName('Sheet28'); let pos = sheet.getDataRange().getValues(); let uniquePos = pos.map(e => e[0]); uniquePos = [...new Set(uniquePos)]; let latests = []; uniquePos.forEach(function (record) { let filteredPo = pos.filter(e => e[0] == record); filteredPo.sort(function (a, b) { let latest = a[1] > b[1] ? 1 : -1; latests.push(latest) }); }) console.log('POS: ' + JSON.stringify(latests)) }
问题分析
当前代码存在几个关键问题:
sort()用法错误:sort()的回调函数需要返回比较值,但你把返回值直接push到latests数组,没有实际完成排序后的行提取。- 字符串时间比较不可靠:直接比较时间字符串可能导致错误(比如"8/18/2022 7:49:49"和"8/17/2022 20:47:59"字符串比较会认为前者更小,但实际时间更晚),必须转为
Date对象比较。 - 未提取排序后的最新行:即使排序正确,也没有将排序后的最后一行(最新行)加入结果数组。
- 未排除表头:
getDataRange()会包含表头,导致uniquePos里包含表头字段,后续处理出错。
修正方案
方案1:高效的对象映射法(推荐)
遍历所有行,用对象存储每个PO的最新行,无需多次过滤排序,性能更优:
function getLastestEntries() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getSheetByName('Sheet28'); const [header, ...rows] = sheet.getDataRange().getValues(); // 分离表头和数据行 const poLatestMap = {}; rows.forEach(row => { const po = row[0]; const currentDate = new Date(row[1]); // 如果当前PO不存在,或当前行时间比已存的更新,就替换 if (!poLatestMap[po] || currentDate > new Date(poLatestMap[po][1])) { poLatestMap[po] = row; } }); // 将对象转为数组,包含表头+最新行 const latests = [header, ...Object.values(poLatestMap)]; console.log('最新行数据:', latests); // 可选:将结果写入新表或覆盖原表 // const targetSheet = ss.getSheetByName('LatestEntries'); // targetSheet.clearContents(); // targetSheet.getRange(1, 1, latests.length, latests[0].length).setValues(latests); }
方案2:修正sort()用法
如果坚持用sort(),调整逻辑如下:
function getLastestEntries() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getSheetByName('Sheet28'); const [header, ...rows] = sheet.getDataRange().getValues(); const uniquePos = [...new Set(rows.map(row => row[0]))]; const latests = [header]; // 先加入表头 uniquePos.forEach(po => { const filteredPo = rows.filter(row => row[0] === po); // 按时间戳降序排序,转为Date对象比较 filteredPo.sort((a, b) => new Date(b[1]) - new Date(a[1])); // 取排序后的第一行(最新行)加入结果 latests.push(filteredPo[0]); }); console.log('最新行数据:', latests); }
说明
- 两种方案都先分离了表头,避免处理表头数据。
- 时间比较都转为
Date对象,确保比较逻辑正确。 - 方案1只需遍历一次数据,比方案2的多次过滤排序更高效,数据量大时差异明显。
内容的提问来源于stack exchange,提问作者onit
相关产品推荐
相关产品推荐

