为什么我在 Google 脚本中对看似完全相同的输入执行 indexOf 操作会得到不一致的结果?

Why do I get inconsistent results from an indexOf action in Google Scripts on what appear to be the exact same inputs?

我试图找到一种在 Google 脚本中搜索数组的方法,但一直找不到任何可行的方法。我的最终目标是对 Google Sheet 中的多个数组进行 vlookup,对它们执行函数,然后将它们推入另一个数组以进行粘贴以供分析。我需要执行大约 2,500 个循环,因此我尽量避免 reading/writing。这是我的主要障碍的一个极其简单的版本。

当我在一个数组中查找数字的索引时,除了 -1 之外我无法得到任何其他内容,除非我正在查找该数组的一个子集。当我寻找不同数组的精确副本或对它进行硬编码时,我得不到一致的结果。预先感谢您的帮助和耐心等待!

这是我 spreadsheet 的 link,这里有一张图片供快速参考:

这是我尝试使用的代码,表明我得到了不同的索引,我认为应该是相同的结果:

    function indexOfTest() {

  //Set sheets
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var dataSheet = ss.getSheetByName("Data");

  //Get ranges
  var dataRange = dataSheet.getRange("A1:B7").getValues(); //data set of the locations I want to search eventually
  var findRange = dataSheet.getRange("E3:E4").getValues(); //values I want to find the row of in the data set (would change in the spreadsheet based on the user's inputs)
  var locationRange = dataSheet.getRange(1,1,dataSheet.getLastRow()).getValues(); //smaller range of the locations I want to locate (1st column) 

  //test showing that indexOf works when I search for a subset of the array within the array
  var findTest1 = locationRange[2]; //set variable to a subset of the array I will search
  var searchResult1 = locationRange.indexOf(findTest1); //finding the index of the subset of the array within the array

  //test showing that indexOf does NOT work when I search for the exact same value in the same array  
  var findTest2 = findRange[0]; //set variable to the the user-entered cell on the sheet which is exactly the same as the subset of the array from the first test
  var searchResult2 = locationRange.indexOf(findTest2); //this comes back as -1 for some reason 

  //test showing that I can't even find it when I hard code it to exactly the same as somethng in the array that I was able to find earlier  
  var findTest3 = [13]; //hardcoded variable to exactly the same as the subset of the array from the first test
  var searchResult3 = locationRange.indexOf(findTest3); //this comes back as -1 for some reason 

  var x = 1 // this is where I have the debug spot (x = 1 is meaningless but wanted the debugger to stop here) 
  // why does the indexOf function work for the first test but not the other two?!?!?!?
  // any help would be greatly appreciated! thanks!

}

当我查看调试器时,我不明白为什么我在两个测试中得到 -1 但它在一个测试中有效...而且他们正在搜索完全相同的东西!

拜托了,非常感谢!

这个答案怎么样?

getValues() 检索到的值是二维数组。

对于您的情况,这是非常重要的一点。

1。准备

作为准备,它确认了dataRangefindRangelocationRangefindTest1findTest2findTest3的值。

检索到dataRangefindRangelocationRange时,如下

dataRange = [["Location #","State"],[11,"AK"],[13,"NE"],[17,"FL"],[24,"IL"],[47,"IL"],[69,"NV"]]
findRange = [[13],["State"]]
locationRange = [["Location #"],[11],[13],[17],[24],[47],[69]]

findTest1findTest2findTest3[13]

2。实验

在这里,它想到了使用 findTest1findTest2findTest3 进行搜索的大约 3 种模式。

模式 1

var findTest1 = locationRange[2];
var searchResult1 = locationRange.indexOf(findTest1);

在这种情况下,from [13] 是从 [["Location #"],[11],[13],[17],[24],[47],[69]] 开始搜索的,即 locationRange。但是 findTest1locationRange 中。这行得通。我认为是因为 indexOf() 可能会使用同一数组中的元素引用来自同一数组的指针。作为另一个示例,请参阅以下示例脚本。

var ar = [[1, 2, 3], [4, 5, 6], [4, 5, 6], [7, 8, 9]];
var r1 = ar.indexOf([4, 5, 6]); // -1
var r2 = ar.indexOf(ar[2]); // 2

在这个脚本中,indexOf() 可以使用同一个二维数组中的元素。在Array.prototype.indexOf()处,当查找的值是一个数组时,可能会引用指针。这个结果对我来说是新发现。

模式 2

var findTest2 = findRange[0];
var searchResult2 = locationRange.indexOf(findTest2);

在这种情况下,from [13] 是从 [["Location #"],[11],[13],[17],[24],[47],[69]] 开始搜索的,即 locationRange。但是 findTest2 不在 locationRange 中。通过这种方式,indexOf() 尝试作为一个值进行搜索。但由于二维数组,它不起作用。如果使用 [13] 搜索指针,也找不到,因为 [13] 不是 locationRange.

中的元素

模式 3

var findTest3 = [13];
var searchResult3 = locationRange.indexOf(findTest3);

在这种情况下,情况与模式2相同。

3。修改脚本

如果你想从locationRange中搜索13,我想你的情况,可以使用下面的修改。在这个修改后的脚本中,searchResult1searchResult2searchResult32.

function indexOfTest2() {
  //Set sheets
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var dataSheet = ss.getSheetByName("Data");

  //Get ranges
  var dataRange = dataSheet.getRange("A1:B7").getValues(); //data set of the locations I want to search eventually
  var findRange = dataSheet.getRange("E3:E4").getValues(); //values I want to find the row of in the data set (would change in the spreadsheet based on the user's inputs)
  var locationRange = dataSheet.getRange(1,1,dataSheet.getLastRow()).getValues(); //smaller range of the locations I want to locate (1st column) 

  // Below script was modified.
  locationRange = Array.prototype.concat.apply([], locationRange);
  var findTest1 = locationRange[2];
  var searchResult1 = locationRange.indexOf(findTest1);
  var findTest2 = findRange[0][0];
  var searchResult2 = locationRange.indexOf(findTest2);
  var findTest3 = [13][0];
  var searchResult3 = locationRange.indexOf(findTest3);
}

注:

  • Array.prototype.concat.apply([], locationRange)[["Location #","State"],[11,"AK"],[13,"NE"],[17,"FL"],[24,"IL"],[47,"IL"],[69,"NV"]] 的二维数组转换为 ["Location #",11,13,17,24,47,69] 的一维数组。
  • findTest1处使用了locationRange[2],因为locationRange是一维数组。
  • findTest2处使用了var findTest2 = findRange[0][0],因为findRange是二维数组。
  • findTest3 处,使用 var findTest3 = [13][0] 因为它从 [13].
  • 检索 13

4。参考资料:

如果这不是你想要的,我很抱歉。

根据 JavaScript 规范,Array#indexOf uses strict equality comparison:

indexOf() compares searchElement to elements of the Array using strict equality (the same method used by the === or triple-equals operator).

严格相等,在相同类型的 Object 的术语中,意味着对象 A 必须是与对象 B 完全相同的对象引用才能使 A === B 成为 true。具有相同值的两个对象并不意味着它们具有相同的对象引用:

var A = ['A', 'B', 'C'];
var B = ['A', 'B', 'C'];
Logger.log(A === B) // false
B = A;
Logger.log(A === B) // true
B = A.slice(0);
Logger.log(A === B) // false
Logger.log(A.map(function (ai, i) { return ai === B[i]; })); // true, true, true

在较新的 JS 版本中,您可以使用 Array#includes 来执行基于值的比较。但是,Apps Script 只是 JS 1.6(带有一些铃声和口哨声),但 includes 不是其中之一。