【问题标题】:Array skips over rows in sheet / removing duplicates with loop issue数组跳过工作表中的行/删除带有循环问题的重复项
【发布时间】:2022-01-13 09:18:02
【问题描述】:

我才开始使用 Apps 脚本几个月,通常我可以弄清楚它为什么会给我错误消息。但是这个最新的让我完全难住了,我找不到任何人在这里问过类似的问题。

我有一个非常简单的代码,它从电子表格中检索数据,循环遍历它以删除一些值,然后再将其粘贴回另一个工作表中。但是,循环不断抛出错误“TypeError:无法读取未定义的属性'0'”。

经过一番挖掘,我想我找到了问题 - 我从工作表中提取的数组比它应该的少了 3 行。

所以var refArray = sheet.getRange("F5:F").getValues(); 的长度为 65,即使工作表中有 68 行。

但真正让我困惑的是,当我运行 var len = refArray.length 时,它返回 68!因此,由于缺乏更好的术语,这使我的循环感到困惑,因为它找不到最后 3 项,并且我得到了上述错误(至少我是这么认为的)。

我尝试使用 var refArray = sheet.getRange(1,6,sheet.getMaxRows(),1) 但这也只是跳过了最后 3 行。没有特别的原因会跳过这些行,有时它只跳过 2 行,所以我认为问题不在于我的数据......

如果有帮助,我可以分享我的工作表和脚本的模型,我不知道它为什么这样做或如何解决它!

已经谢谢大家了。

编辑

我可能一直在寻找错误的树,因为我只是试图在另一张表中复制问题并且数组似乎被正确提取,但是当它开始循环时再次弹出错误。正如我所说,我只是涉足 Apps 脚本,所以我的循环非常基本。我只是要在下面添加完整的序列,看看是否有人能发现错误:

var s = SpreadsheetApp.getActive();
var sheet = s.getSheetByName("Sheet1");
var sheet2 = s.getSheetByName("Sheet2");

function test() {
  
  // get archive Array
  var archiveArray = sheet2.getRange("A3:A").getValues();
  console.log("Array Check: "+archiveArray[0][0]);

  // get ref Array to loop through
  var refArray = sheet.getRange("F2:F").getValues();
  console.log("Array Check: "+refArray[0][0]); // length 29

  var len = refArray.length; 
  console.log(len); // length 29

  for ( var l = len - 1; l > 0; l--){ 
    for( var a = 0; a < archiveArray.length; a++) {
      if ( archiveArray[a][0] == refArray[l][0] ) {
        refArray.splice(l,1);                         // remove all duplicates
      }
    }
  }

  console.log("New array:"+refArray);

【问题讨论】:

  • 显示你的代码,尤其是for循环部分。
  • 当条件匹配时,refArray 的长度会减少,在某些情况下会出现上述错误。你最好复制数组并对其执行splice
  • 谢谢。我认为当单独声明“len”时,即使数组本身变短,值也不会改变,还是错了?另外,我如何“复制”一个数组?我是否只需将每个值 array.push 到一个新数组中?
  • 我说的是实际长度,len 无关紧要。

标签: javascript arrays google-apps-script google-sheets


【解决方案1】:

我建议使用array.includes() 方法并创建一个新数组而不是更改现有数组:

有一个循环:

var archiveArray = ['a', 'b', 'c', 'd'];
var refArray = ['a', 'b', 'e', 'f'];
var new_refArray = [];

for (var val of refArray) {
    if (!archiveArray.includes(val)) new_refArray.push(val)
}
    
console.log(new_refArray); // output [ 'e', 'f' ]

或者使用过滤器:

var archiveArray = ['a', 'b', 'c', 'd'];
var refArray = ['a', 'b', 'e', 'f'];
var new_refArray = refArray.filter(val => !archiveArray.includes(val));

console.log(new_refArray); // output [ 'e', 'f' ]

最终的代码可以是这样的:

var s = SpreadsheetApp.getActive();
var sheet = s.getSheetByName("Sheet1");
var sheet2 = s.getSheetByName("Sheet2");

function test() {
  var archiveArray = sheet2.getRange("A3:A").getValues()
    .flat().filter(String); // convert 2D into 1D and remove empty elements

  var refArray = sheet.getRange("F2:F").getValues()
    .flat().filter(String); // convert 2D into 1D and remove empty elements

  var new_refArray = refArray.filter(val => !archiveArray.includes(val));

  console.log(new_refArray);
}

注意:如果要将结果数组粘贴回工作表上,则它应该是二维数组。您可以通过这种方式将平面数组转换为二维数组:

new_refArray = new_refArray.map(x => [x]); // [a,b,c] --> [[a],[b],[c]]

【讨论】:

  • 谢谢,我已经尝试了这两个建议并且它们运行没有错误,但是不幸的是,它们都没有删除我数组中的任何重复项。
  • 他们不应该删除任何东西。关键是创建一个具有非重复值的新数组(archiveArray 中不存在的值)。这两个 sn-ps 都为您提供了包含唯一值的新数组。仅: ['e', 'f'] 在这种情况下。这与从 refArray 中删除值 'a'、'b' 相同。
  • 对不起,我应该换个说法。我的意思是当我在我的脚本中尝试这些时,新数组是原始数组的精确副本,它仍然包含重复的值。
  • 我认为这可能是因为您的样本中的数组是二维数组。但是我的 sn-ps 中的数组是一维数组。如果你愿意,我可以告诉你如何处理它。
  • 我在答案中添加了代码,该代码显示了如何使用 flat() 方法将二维数组转换为一维数组,并使用 filter(String) 方法从数组中删除空元素。
【解决方案2】:

由于.splice 删除了一个元素,因此相应地调整索引l

refArray.splice(l,1);
--l;//adjust index by 1

【讨论】:

    猜你喜欢
    • 2021-03-10
    • 2011-07-21
    • 1970-01-01
    • 1970-01-01
    • 2016-09-20
    • 1970-01-01
    • 2011-11-30
    • 2021-10-24
    • 1970-01-01
    相关资源
    最近更新 更多