【问题标题】:Row count off by one in google spreadsheet谷歌电子表格中的行数减一
【发布时间】:2012-11-18 10:06:30
【问题描述】:

我想删除空行。第 885 行是非空行,应保留。但是,我的代码说(并在 msgbox 中显示)885 是空的,应该删除。当它到达 i=884 时,它会打印第 885 行中的实际内容,并说它不会被删除。所以,我很困惑。它似乎正确地作用于数据,但它报告的行号错误。我怀疑你会告诉我偏移量是从零开始的,并且行从 1 开始,所以如果 lastrow=888(从 1 开始),那么我需要减去 1 来匹配偏移量。所以我在电子表格中看到的第 885 行实际上是第 884 行作为偏移量。

但是...当 i=885 行有数据时,偏移量为 884。而当 i=884 时,偏移量为 883...那为什么要打印第 885 行的内容?这里严重混淆。我哪里错了?

最后但最重要的是......它删除了错误的行!怎么可能引用了正确的数据,却仍然删除了错误的行???

var s = SpreadsheetApp.getActiveSheet();
var range = SpreadsheetApp.getActiveSheet().getDataRange();
var i = range.getLastRow();
var msg;
var colNum;

for (; i > 1; i--) {  // I like to start at the end
  var foundAvalue=0;  // reset flag for each row

  rowRange = range.offset(i, 0, 1); 

  var valArray=rowRange.getValues();
  var foundAvalue=0;
  var msg;
  var totalColumns=rowRange.getNumColumns();

   colNum=0;   

   while (colNum < totalColumns && (foundAvalue==0)) {
     if (valArray[0][colNum] != '') {       
       foundAvalue=1; 
       msg="Row " + i + " =" + valArray[0];
       Browser.msgBox(msg);
       msg="Row " + i + " will not be deleted";
       Browser.msgBox(msg);
     }
     colNum++;
   }
   if (foundAvalue == 0) {
      msg="Row " + i + " =" + valArray[0] + "WILL be deleted";
      Browser.msgBox(msg);
           // delete empty row
      // s.deleteRow(i);
   }

 } // end for(i)  

【问题讨论】:

  • 对于未来出现的任何人...... RocketDonkey 帮助我理解了上述代码的基本问题是 offset() 函数需要“i-1”,而我只是在这里使用“我”。
  • 原因是 offset() 将它的答案作为基于零的值返回。所以我的范围通常是 1 到 LastRow 被偏移量返回为 0 到 LastRow-1。必须小心,因为像 deleteRow() 这样的函数需要从 1 到 LastRow 的一行,而不是从零开始。

标签: google-apps-script google-sheets


【解决方案1】:

下面是一些应该完成你想要的代码。您是正确的,问题的根源在于基于 0 的索引。棘手的部分是 JavaScript/Apps 脚本数组使用从 0 开始的索引,但是当你调用类似 getLastRow() 的东西时,返回的范围是从 1 开始的。总而言之,您的代码很好 - 只是那个问题让您感到困惑。希望这会有所帮助:

function DeleteFun(){
  var mySheet = SpreadsheetApp.getActiveSheet();
  var range = mySheet.getDataRange();

  // Iterate using a counter, starting at the last row and stopping at
  // the header (assumes the header is in the first row)
  for (i = mySheet.getLastRow() - 1; i > 0; i--) {
    var foundAvalue = 0;
    // Here we get the values for the current row and store in an array
    rowRange = range.getValues()[i]
    // Now we iterate through that array
    for (j = 0; j <= rowRange.length; j++) {
      // If any non-nulls are found, alert they won't be deleted and move on
      if (rowRange[j] != null && rowRange[j] != '') {
        foundAvalue = 1; 
        msg="Row " + (i+1) + " =" + rowRange[0] + " and will not be deleted";
        Browser.msgBox(msg);
        break;
       }
    }

    if (foundAvalue == 0) {
      msg="Row " + (i+1) + " =" + rowRange[0] + "WILL be deleted";
      Browser.msgBox(msg);
      // Delete empty row
      mySheet.deleteRow(i+1);
    }
  }
}

【讨论】:

  • 好的,所以看起来您正在从 lastRow - 1 开始行计数器“i”,这意味着 i 被用作数组的索引。所以“getvalues”显然是返回一个从零开始的范围。嗯。我仍然没有看到它。您正在获取一行数据,并将其填充到一个数组中。因此,过去的“rowNum”现在通过数组寻址为“rowNum - 1”,以适应基于零的索引。因此,如果我的数据从第 1 行到第 888 行,则数组索引为 0 到 887。我明白了,而且一直都有。现在,由于您没有对 deleteRow 进行任何更改 - 仅被评论(续)
  • getLastRow 部分返回实际的行号(从 1 开始),因此我们减 1 以允许 getValues[i] 函数正确引用它返回的从 0 开始的数组。那有意义吗?很乐意提供帮助,直到清楚为止:)
  • 所以我不会丢失数据...我猜 deleteRow 也需要基于零的索引?好的,你和我所做的主要区别似乎是我使用“偏移”函数来使用 rowNum 获取范围,而你消除了这一步。您使用 rowNum-1 获得了范围。所以你得到的是第 887 行而不是第 888 行。我不明白为什么这样会更好。现在我们简单地跳过最后一行并包括我不需要处理的第一行 - 标题 - 行。我仍然不明白为什么我的代码删除了错误的行。你测试过你的代码吗?
  • 是的,我了解 getLastRow 的作用……而且我了解数组是从零开始的。但正如我在您输入时提到的那样......看来您的代码正在获取 LastRow-1 并跳过可能包含或不包含数据的 lastRow 。我显然仍然缺少一些东西。我怀疑我使用的 offset() 函数可能是关键?
  • @AB 现在远离电脑,但我会尽可能给出更详细的答案。不使用偏移量可以避免额外的函数调用,但本质上是相同的。至于标题行,我的错 - 我的数据没有。要进行调整,请修改主循环,使最终条件为i &gt; 0(假设它在第一行,它将在碰到标题时停止)。我将重新测试这些调整,但它以前工作过。另外,我建议使用Logger.log() 作为一种测试方式——您可以运行该函数并在脚本编辑器中按Control+Enter 以查看输出。
【解决方案2】:

如果您不在工作表中使用公式,您也可以在“纯”数组中执行此操作。

例如这样:

function deleteEmptyRows(){ 
 var sh = SpreadsheetApp.getActiveSheet();
 var data = sh.getDataRange().getValues();
 var targetData = new Array();
 for(n=0;n<data.length;++n){
 if(data[n].join().replace(/,/g,'')!=''){ targetData.push(data[n])};// checks the whole row
 Logger.log(data[n].join().replace(/,/g,''))
 }
 sh.getDataRange().clear(); // clear the whole sheet
 sh.getRange(1,1,targetData.length,targetData[0].length).setValues(targetData);//write back all non empty rows
 }

【讨论】:

  • 嗯,感谢您提供完成工作的替代方法。让我有新的东西要学习...加入、替换、推动...我相信有一天我会调查这一切...
  • 阵列就像巧克力:一旦你尝过就无法抗拒 ;-) 试一试就会被感染!!
  • 我对数组非常熟悉。我的大脑不仅要花时间处理,还要研究其他未知数。我在营火上烧水。你刚刚在微波炉里煮了茄子帕尔马干酪,并告诉我也这样做。这会是一段时间。但是感谢您让我知道那里有什么!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多