线性化 BOM,使用 setValues(result) 而不是 appendRow 时出现问题

Linearize a BOM, issue when using setValues(result) instead of appendRow

输入如下(这是一个简化的例子)

LEVEL NAME JOB
1 A Alpha
2 B Bravo
3 C Charlie
4 D Delta
2 E Echo
3 F Foxtrot
2 G Golf
2 H Hotel
3 I India
4 J Juliet

我必须线性化才能获得该输出

NAME level 1 JOB level 1 NAME level 2 JOB level 2 NAME level 3 JOB level 3 NAME level 4 JOB level 4
A Alpha B Bravo C Charlie D Delta
A Alpha E Echo F Foxtrot
A Alpha G Golf
A Alpha H Hotel I India J Juliet

我通过使用临时数组 (temp) 和 appendRow 来实现,这有点慢。当我设法使用大数组(结果)和 setValues(结果)时,我只得到最后一行

NAME level 1 JOB level 1 NAME level 2 JOB level 2 NAME level 3 JOB level 3 NAME level 4 JOB level 4
A Alpha H Hotel I India J Juliet
A Alpha H Hotel I India J Juliet
A Alpha H Hotel I India J Juliet
A Alpha H Hotel I India J Juliet

我不明白我的脚本有什么问题!任何帮助理解都会有用。

https://docs.google.com/spreadsheets/d/1zoT9kk-Am_yUOLCAAvccJOTH0UZ7lrRiLYpPtqb9RXY/copy

function linearize() {
  const sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Original')
  const data = sh.getRange(2, 1, sh.getLastRow() - 1, sh.getLastColumn()).getDisplayValues()
  const nbData = sh.getLastColumn() - 1

  const bd1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('BD1') // for test with appendrow
  const bd2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('BD2') // for test with result
  bd1.clearContents()
  bd2.clearContents()

  let result = []
  let levelMax = 0
  let headers = []
  data.forEach(r => levelMax = Math.max(levelMax, r[0]))
  for (let i = 1; i <= levelMax; i++) {
    headers.push(['NAME level ' + i, 'JOB level ' + i])
  }
  bd1.appendRow(headers.flat())
  result.push(headers.flat())
  // everything ok until this step ==============
  let temp = []
  data.forEach(function (r, i) {
    // save values
    var level = r[0]
    for (let x = 0; x < nbData; x++) {
      temp[nbData * (level - 1) + x] = r[x + 1]
    }
    // blank values from level+1 to levelMax
    if (level < levelMax) {
      for (let y = (level * 1 + 1); y <= levelMax; y++) {
        for (let x = 0; x < nbData; x++) {
          temp[nbData * (y - 1) + x] = ''
        }
      }
    }
    // output when the following level will not increase or at the final row
    if (i < data.length - 1) {
      if (data[i + 1][0] <= data[i][0]) {
        bd1.appendRow(temp)
        result.push(temp)
      }
    }
    else {
      bd1.appendRow(temp)
      result.push(temp)
    }

  })
  bd2.getRange(1, 1, result.length, result[0].length).setValues(result)
}

我相信你的目标如下。

  • 通过修改脚本,您想使用bd2.getRange(1, 1, result.length, result[0].length).setValues(result).
  • 实现I have to linearize to obtain that output的情况

这样的话,下面的修改怎么样?

发件人:

if (i < data.length - 1) {
  if (data[i + 1][0] <= data[i][0]) {
    bd1.appendRow(temp)
    result.push(temp)
  }
}

收件人:

if (i < data.length - 1) {
  if (data[i + 1][0] <= data[i][0]) {
    bd1.appendRow(temp);
    result.push([...temp]); // <--- Modified. Or result.push(temp.slice())
  }
}
  • 我认为在您的脚本中,temp 用作 pass-by-reference。这样就出现了I only get the last row的问题。我认为这可能是您遇到问题的原因。因此,在这种情况下,temp[...temp] and/or temp.slice() 一起复制。这样,它就变成了 pass-by-value.