使用 Google Apps 脚本替换数组中的行
Replace Rows in Array using Google Apps Script
我仍在研究 Apps 脚本,只是需要一些帮助来编辑数组。
所以我有两个数组:
var arrayBig = SpreadsheetApp.getSheetByName('Big').getDataRange().getValues();
var arraySmall = SpreadsheetApp.getSheetByName('Small').getDataRange().getValues();
我想根据 arraySmall
中的值替换 arrayBig
中的特定行,然后将该数组写回我的电子表格(我同意的最后一部分)。
两个数组的列数相同,但arraySmall
行数较少。
要替换的行数:
- 根据
arraySmall
中第 1 列的数值替换 arrayBig
中的行。
因此,如果第 1 列中的值 = 3 将 arrayBig
中的行号 3 替换为 arraySmall
中第 1 列 = 3.
中行的内容
我认为答案与 map method 有关,但我不明白。非常感谢您提供一些帮助我入门的建议,谢谢。
这是一种“入门”方法:
你描述了你的数据,但你没有提供任何具体的样本 - 所以这是我的起始数据,根据问题中的信息做出一些假设:
var arrayBig = [ [1, "A", "B"], [2, "C", "D"], [3, "E", "F"], [4, "G", "H"] ];
var arraySmall = [ [1, "P", "Q"], [3, "Y", "Z"] ];
根据以上数据,预期结果如下,其中第 1 行和第 3 行被替换:
[ [1, "P", "Q"], [2, "C", "D"], [3, "Y", "Z"], [4, "G", "H"] ];
方法如下:
var arrayBig = [ [1, "A", "B"], [2, "C", "D"], [3, "E", "F"], [4, "G", "H"] ];
var arraySmall = [ [1, "P", "Q"], [3, "Y", "Z"] ];
var mapper = new Map();
arraySmall.forEach((row) => {
mapper.set(row[0], row);
} );
newArrayBig = [];
arrayBig.forEach((row) => {
if ( mapper.has( row[0] ) ) {
newArrayBig.push( mapper.get( row[0] ) );
} else {
newArrayBig.push( row );
}
} );
console.log( newArrayBig );
这假设您有一个铁定的保证 arraySmall
中的数据行绝不会多于 arrayBig
中的数据行。您可以(并且应该)添加一些逻辑来对此进行测试,以获得更健壮的代码。
备注
Map
对象(不是 map()
方法)是这种方法的核心。这个对象提供了一个查找结构:一个索引值,指向一个数据值:
var mapper = new Map();
arraySmall.forEach((row) => {
mapper.set(row[0], row);
} );
在我们的例子中,索引是每个 arraySmall
行第一个单元格中的数字。它指向的值是该行的完整数据数组,例如:
1 -> [1, "P", "Q"]
3 -> [3, "Y", "Z"]
我们现在可以在遍历 arrayBig
数据的每一行时使用此查找数据:
arrayBig.forEach((row) => { ... } );
这个 forEach
迭代器中的逻辑基本上是这样说的:如果映射包含一个使用与当前 arrayBig
行相同编号的数组,则使用 arraysmall
数据。否则,使用 arrayBig
数据。
newArrayBig.push()
方法将该数组添加到我们的结果数组中。
然后您可以根据需要将其写回您的电子表格。
以防万一。另一个解决方案:
var arrayBig = [ [1,"A","B"], [2,"C","D"], [3,"E","F"], [4,"G","H"] ];
var arraySmall = [ [1,"P","Q"], [3,"Y","Z"] ];
var obj = {}; // it will be { "1":[1,"P","Q"], "3": [3,"Y","Z"] }
arraySmall.forEach( x => obj[x[0]] = x );
arrayBig = arrayBig.map( x => obj[x[0]] || x );
console.log(arrayBig); // [[1,"P","Q"], [2,"C","D"], [3,"Y","Z"], [4,"G","H"]];
它将小数组转换为一个对象,其中每行的第一个元素是一个键,该行是它的值。然后它遍历大数组并尝试通过键(第一个单元格)获取对象的值。如果键存在,行将被替换,如果键不存在,for 不会改变。
小数组中的行顺序也无关紧要。
更新
如果需要,您可以使用数组代替对象:
var arrayBig = [ [1,"A","B"], [2,"C","D"], [3,"E","F"], [4,"G","H"] ];
var arraySmall = [ [1,"P","Q"], [3,"Y","Z"] ];
var arr = [];
arraySmall.forEach( x => arr[x[0]-1] = x ); // [ [1,"P","Q"], [], [3,"Y","Z"], [] ];
arrayBig = arrayBig.map( (x,i) => arr[i] || x);
console.log(arrayBig);
我认为这会占用更多内存,但它确实有效。但是你需要确保第一个单元格只包含数字,因为它们用作数组的索引(数组的索引应该是数字,不像键可以是任何东西)。第一个数组的行应该排序并且没有跳过的数字(1、2、3、4 等)。所以,这是一个更脆弱的解决方案。仅用于教育目的。
我仍在研究 Apps 脚本,只是需要一些帮助来编辑数组。
所以我有两个数组:
var arrayBig = SpreadsheetApp.getSheetByName('Big').getDataRange().getValues();
var arraySmall = SpreadsheetApp.getSheetByName('Small').getDataRange().getValues();
我想根据 arraySmall
中的值替换 arrayBig
中的特定行,然后将该数组写回我的电子表格(我同意的最后一部分)。
两个数组的列数相同,但arraySmall
行数较少。
要替换的行数:
- 根据
arraySmall
中第 1 列的数值替换arrayBig
中的行。
因此,如果第 1 列中的值 = 3 将 arrayBig
中的行号 3 替换为 arraySmall
中第 1 列 = 3.
我认为答案与 map method 有关,但我不明白。非常感谢您提供一些帮助我入门的建议,谢谢。
这是一种“入门”方法:
你描述了你的数据,但你没有提供任何具体的样本 - 所以这是我的起始数据,根据问题中的信息做出一些假设:
var arrayBig = [ [1, "A", "B"], [2, "C", "D"], [3, "E", "F"], [4, "G", "H"] ];
var arraySmall = [ [1, "P", "Q"], [3, "Y", "Z"] ];
根据以上数据,预期结果如下,其中第 1 行和第 3 行被替换:
[ [1, "P", "Q"], [2, "C", "D"], [3, "Y", "Z"], [4, "G", "H"] ];
方法如下:
var arrayBig = [ [1, "A", "B"], [2, "C", "D"], [3, "E", "F"], [4, "G", "H"] ];
var arraySmall = [ [1, "P", "Q"], [3, "Y", "Z"] ];
var mapper = new Map();
arraySmall.forEach((row) => {
mapper.set(row[0], row);
} );
newArrayBig = [];
arrayBig.forEach((row) => {
if ( mapper.has( row[0] ) ) {
newArrayBig.push( mapper.get( row[0] ) );
} else {
newArrayBig.push( row );
}
} );
console.log( newArrayBig );
这假设您有一个铁定的保证 arraySmall
中的数据行绝不会多于 arrayBig
中的数据行。您可以(并且应该)添加一些逻辑来对此进行测试,以获得更健壮的代码。
备注
Map
对象(不是 map()
方法)是这种方法的核心。这个对象提供了一个查找结构:一个索引值,指向一个数据值:
var mapper = new Map();
arraySmall.forEach((row) => {
mapper.set(row[0], row);
} );
在我们的例子中,索引是每个 arraySmall
行第一个单元格中的数字。它指向的值是该行的完整数据数组,例如:
1 -> [1, "P", "Q"]
3 -> [3, "Y", "Z"]
我们现在可以在遍历 arrayBig
数据的每一行时使用此查找数据:
arrayBig.forEach((row) => { ... } );
这个 forEach
迭代器中的逻辑基本上是这样说的:如果映射包含一个使用与当前 arrayBig
行相同编号的数组,则使用 arraysmall
数据。否则,使用 arrayBig
数据。
newArrayBig.push()
方法将该数组添加到我们的结果数组中。
然后您可以根据需要将其写回您的电子表格。
以防万一。另一个解决方案:
var arrayBig = [ [1,"A","B"], [2,"C","D"], [3,"E","F"], [4,"G","H"] ];
var arraySmall = [ [1,"P","Q"], [3,"Y","Z"] ];
var obj = {}; // it will be { "1":[1,"P","Q"], "3": [3,"Y","Z"] }
arraySmall.forEach( x => obj[x[0]] = x );
arrayBig = arrayBig.map( x => obj[x[0]] || x );
console.log(arrayBig); // [[1,"P","Q"], [2,"C","D"], [3,"Y","Z"], [4,"G","H"]];
它将小数组转换为一个对象,其中每行的第一个元素是一个键,该行是它的值。然后它遍历大数组并尝试通过键(第一个单元格)获取对象的值。如果键存在,行将被替换,如果键不存在,for 不会改变。
小数组中的行顺序也无关紧要。
更新
如果需要,您可以使用数组代替对象:
var arrayBig = [ [1,"A","B"], [2,"C","D"], [3,"E","F"], [4,"G","H"] ];
var arraySmall = [ [1,"P","Q"], [3,"Y","Z"] ];
var arr = [];
arraySmall.forEach( x => arr[x[0]-1] = x ); // [ [1,"P","Q"], [], [3,"Y","Z"], [] ];
arrayBig = arrayBig.map( (x,i) => arr[i] || x);
console.log(arrayBig);
我认为这会占用更多内存,但它确实有效。但是你需要确保第一个单元格只包含数字,因为它们用作数组的索引(数组的索引应该是数字,不像键可以是任何东西)。第一个数组的行应该排序并且没有跳过的数字(1、2、3、4 等)。所以,这是一个更脆弱的解决方案。仅用于教育目的。