【问题标题】:Comparing two 2D arrays with different length for matches比较两个不同长度的二维数组进行匹配
【发布时间】:2020-05-25 07:54:04
【问题描述】:

我在为 Google 表格编写一个小脚本时遇到了一个问题。我想做的基本事情是获取整列的条目并将其与可能具有不同长度的不同工作表的另一列的条目进行比较。然后匹配的条目应该被推送到另一个数组,并且在第一张表的另一列中,每一行都应该标有“已经在其他电子表格中”,其中一个匹配条目出现。

第一张表的第一列包含 5 个元素 [从第 1 行开始] banana apple cucumber strawberry raspberry

第二张表的第二列包含 9 个元素 [从第 1 行开始] tomato pineapple strawberry walnut apple watermelon kiwi banana raspberry

这是目前为止的基本代码:

    function arraycompare() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = SpreadsheetApp.getActiveSheet();
  var ss1 = SpreadsheetApp.openById("...Sheet_ID...");
  var sheet1 = ss1.getSheetByName("Sheet1");

  var lastrow = sheet.getLastRow();
  var lastrow1 = sheet1.getLastRow();

  var range = sheet.getRange(1, 1, lastrow, 1);
  var sheetdata = range.getValues();

  var range1 = sheet1.getRange(1, 2, lastrow, 1);
  var sheet1data = range1.getValues();

  var match = [];
for (var x = 0; x < sheetdata.length; x++) {
  for (var y = 0; y < sheetdata[x].length; y++) {
     for(var i = 0; i < sheet1data.length; i++){
       for(var j = 0; j < sheet1data[i].length; j++){
         if (sheetdata[x][y] == sheet1data[i][j]){
           sheet.getRange(x, 2).setValue("Already in other Spreadsheet");
           match.push(sheetdata[x][y]);
         };
       };
     };
  };
};

  //test
  Logger.log(match);

};

记录器的输出只是将[apple, strawberry] 显示为匹配项,而不是覆盆子。我假设 for 循环在 5 个元素处停止,但我真的不明白为什么以及如何用 2d 数组解决这个问题?

此外,“已经在电子表格中”的概念出现在第 2 行中香蕉和黄瓜的行位置,而不是与苹果和草莓在同一行。真的很想知道,我在这里做错了什么以及如何解决这个问题以获得更好的理解。

希望你们能帮帮我。提前非常感谢。

【问题讨论】:

  • 我认为你的问题是由于错误的变量和范围的第一个索引。那么如何将var range1 = sheet1.getRange(1, 2, lastrow, 1); 修改为var range1 = sheet1.getRange(1, 2, lastrow1, 1); 并将sheet.getRange(x, 2).setValue("Already in other Spreadsheet"); 修改为sheet.getRange(x + 1, 2).setValue("Already in other Spreadsheet");
  • Ouuch :D 这可能为我节省了数小时的 for 循环以及为什么它没有按预期工作,非常感谢 :)
  • 感谢您的回复。很高兴您的问题得到解决。

标签: javascript google-apps-script multidimensional-array google-sheets comparison


【解决方案1】:

我建议进行以下更改:

(1) 当您使用单列数据时,您不需要变量yj

sheetdata[x][0] 将是数组第 x 行中字符串的值。

sheet1data[i][0] 将是数组第i 行中字符串的值。

(2) 数组是从零开始的,即数组中的第一个“行”是 0。而工作表上的第一行是 1。

所以当为数组中的第 xth 行写入工作表时,需要写入工作表上的第 x+1 th 行。

以下是for 循环在进行这些更改后的样子:

  for (var x = 0; x < sheetdata.length; x++) {
    for(var i = 0; i < sheet1data.length; i++){
      if (sheetdata[x][0] == sheet1data[i][0]){
        sheet1.getRange(x + 1, 2).setValue("Already in other Spreadsheet");
        match.push(sheetdata[x][0]);
      };
    };
  };

正如Tanaike-san所说,lastRow1应该用于计算range1而不是lastRow

  var range1 = sheet1.getRange(1, 2, lastrow1, 1);

【讨论】:

  • 非常感谢您的解释 :) 这完全有道理,但同时您通过 range(1,1).getValue() 获得第一个单元格的值有点令人困惑,至少对我来说:D,但我想我现在明白了,它的行为就像一个数组,谢谢 :)
【解决方案2】:

试试这个:

//V8 version
function arraycompare() {
  const ss1=SpreadsheetApp.getActive();
  const sh1=ss1.getSheetByName('Sheet1');
  const rg1=sh1.getRange(1,1,sh1.getLastRow(),1);
  let v1=rg1.getValues().map(function(r){return r[0];});//this flattens the single column 2d array
  const sh3=ss1.getSheetByName('Sheet3');
  sh3.clearContents();
  const ss2id="Spreadsheet 2 id";
  const ss2=SpreadsheetApp.openById(ss2id);
  const sh2=ss2.getSheetByName("Sheet1");
  const rg2=sh2.getRange(1,1,sh2.getLastRow(),1);
  let v3=[['Value','Spreadsheet1 Sheet 1Row','Status','Spreadsheet2Id','Spreadsheet2 Sheet1 Row']];
  let v2=rg2.getValues().map(function(r){return r[0];});
  v1.forEach(function(e,i){
    let idx=v2.indexOf(e);
    if(idx!=-1) {
      v3.push([e,i+1,'Already in other Spreadsheet',ss2id,idx+1]);
    }
  });
  sh3.getRange(1,1,v3.length,v3[0].length).setValues(v3);
} 

//Javascript 1.6 Version
function arraycompare1() {
  var ss1=SpreadsheetApp.getActive();
  var sh1=ss1.getSheetByName('Sheet1');
  var rg1=sh1.getRange(1,1,sh1.getLastRow(),1);
  var v1=rg1.getValues().map(function(r){return r[0];});//this flattens the single column 2d.
  var sh3=ss1.getSheetByName('Sheet3');
  sh3.clearContents();
  var ss2id="Spreadsheet 2 id";
  var ss2=SpreadsheetApp.openById(ss2id);
  var sh2=ss2.getSheetByName("Sheet1");
  var rg2=sh2.getRange(1,1,sh2.getLastRow(),1);
  var v3=[['Value','Spreadsheet1 Sheet 1Row','Status','Spreadsheet2Id','Spreadsheet2 Sheet1 Row']];
  var v2=rg2.getValues().map(function(r){return r[0];});
  v1.forEach(function(e,i){
    var idx=v2.indexOf(e);
    if(idx!=-1) {
      v3.push([e,i+1,'Already in other Spreadsheet',ss2id,idx+1]);
    }
  });
  sh3.getRange(1,1,v3.length,v3[0].length).setValues(v3);
} 

电子表格1:

banana
apple
cucumber
strawberry
raspberry

电子表格2:

tomato
pineapple
strawberry
walnut
apple
watermelon
kiwi
banana
raspberry

最终输出

Value,Spreadsheet1 Sheet 1Row,Status,Spreadsheet2Id,Spreadsheet2 Sheet1 Row
banana,1,Already in other Spreadsheet,xxx,8
apple,2,Already in other Spreadsheet,xxx,5
strawberry,4,Already in other Spreadsheet,xxx,3
raspberry,5,Already in other Spreadsheet,xxx,9

【讨论】:

  • sweet :) 就像一个魅力,感谢您为 v8 提供示例:)
  • 我的 V8 示例可能无法真正反映 ES6 的强大功能,因为我才刚刚开始学习。
【解决方案3】:

您也可以使用flatincludes 执行此操作:

//simulate `getValues()` column data
const sheet1data = [["banana"],["apple"],["cucumber"],["strawberry"],["raspberry"]];
const sheet2data = [["tomato"],["pineapple"],["strawberry"],["walnut"],["apple"],["watermelon"],["kiwi"],["banana"],["raspberry"]];
const str = "Already in sheet2";
const sheet2_1d = sheet2data.flat();
const out = sheet1data.map(([fruit])=> sheet2_1d.includes(fruit) ? [fruit, str] : [fruit, null]);
console.log(out);//setvalues this out array

【讨论】:

  • 很好,我不知道那个方法,会检查一下:) 非常感谢
猜你喜欢
  • 1970-01-01
  • 2013-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-17
  • 2020-04-05
  • 2014-04-23
  • 1970-01-01
相关资源
最近更新 更多