我的google电子表格中有两个工作表:
输入数据通过Get Data
函数进入importxml
工作表。
但是,我想将Get Data
工作表的所有值复制到Final Data
工作表,如果有重复项(按行数),请附加唯一的行。
以下是我的尝试:
function onEdit() {
//get the data from old Spreadsheet
var ss = SpreadsheetApp.openById("1bm2ia--F2b0495iTJotp4Kv1QAW-wGUGDUROwM9B-D0");
var dataRange = ss.getSheetByName("Get Data").getRange(1, 1, ss.getLastRow(), ss.getLastColumn());
var dataRangeFinalData = ss.getSheetByName("Final Data").getRange(1, 1, ss.getLastRow(), ss.getLastColumn());
var myData = dataRange.getValues();
//Open new Spreadsheet & paste the data
newSS = SpreadsheetApp.openById("1bm2ia--F2b0495iTJotp4Kv1QAW-wGUGDUROwM9B-D0");
Logger.log(newSS.getLastRow());
newSS.getSheetByName("Final Data").getRange(newSS.getLastRow()+1, 1, ss.getLastRow(), ss.getLastColumn()).setValues(myData);
//remove duplicates in the new sheet
removeDups(dataRangeFinalData)
}
function getId() {
Browser.msgBox('Spreadsheet key: ' + SpreadsheetApp.getActiveSpreadsheet().getId());
}
function removeDups(array) {
var outArray = [];
array.sort(lowerCase);
function lowerCase(a,b){
return a.toLowerCase()>b.toLowerCase() ? 1 : -1;// sort function that does not "see" letter case
}
outArray.push(array[0]);
for(var n in array){
Logger.log(outArray[outArray.length-1]+' = '+array[n]+' ?');
if(outArray[outArray.length-1].toLowerCase()!=array[n].toLowerCase()){
outArray.push(array[n]);
}
}
return outArray;
}
您可以在下面找到示例电子表格的链接:
我的问题是数据没有被粘贴。
感谢您的回复!
答案 0 :(得分:1)
tl; dr:请参阅底部的脚本。
onEdit()
函数不适合您的用例,因为电子表格函数修改的单元格内容不被视为“编辑”事件。您可以阅读有关in this answer的更多信息。如果您希望自动化,那么定时触发功能将是合适的。或者,您也可以通过菜单项手动调用该功能。我会留给你决定,因为问题的真正原因在于如何确保最终数据集中的行级唯一性。
虽然您的原始代码不完整,但似乎您打算首先从源数据中删除重复项,并使用不区分大小写的字符串比较。我会建议其他一些JavaScript魔法在这里会有所帮助。
我们对目标数据的唯一性感兴趣,因此我们需要有一种方法来比较新行和我们已有的行。如果我们有字符串或数字的数组,那么我们可以使用How to merge two arrays in Javascript and de-duplicate items中的技术。但是,这里有一个复杂的问题,因为我们有一个数组数组,并且无法直接比较数组。
很好 - 我们仍然可以逐个元素地比较行,这需要在我们比较的行中的所有列上进行简单的循环。简单,但很慢,我们称之为O(n2) solution (顺序为n平方)。随着要比较的行数增加,唯一比较操作的数量将呈指数增长。所以,我们不要这样做。
相反,我们将创建一个独立的数据结构来反映我们的目标数据,但对于比较非常有效,hash。
在JavaScript中,我们可以通过名称或密钥快速访问对象的属性。此外,该密钥可以是任何字符串。我们可以创建一个简单的哈希表,使用一个对象,其属性使用从目标数据行生成的字符串命名。例如,这将创建一个哈希对象,然后将数组row
添加到它:
var destHash = {};
destHash[row.join('')] = true; // could be anything
要创建我们的密钥,我们join
row
数组中没有分隔符的所有值。现在,为了测试行的唯一性,我们只检查是否存在具有相同形式的键的对象属性。像这样:
var alreadyExists = destHash.hasOwnProperty(row.join(''));
另外一个考虑因素:由于源数据可能包含尚未包含在目标数据中的重复行,因此我们需要在识别唯一行时不断扩展哈希表。
JavaScript提供了两个内置数组方法,我们将filter用于已知行,concatenate只有唯一的目标数据行。
以简单的形式,如下所示:
// Concatentate source rows to dest rows if they satisfy a uniqueness filter
var mergedData = destData.concat(sourceData.filter(function (row) {
// Return true if given row is unique
}));
您可以将其视为“创建一个名为mergedData
的数组,该数组由名为destData
的数组的当前内容组成,其中sourceData
数组的已过滤行与其连接。”
你会在最后的函数中发现,由于已经提到的其他考虑因素,它会更复杂一些。
我们拥有mergedData
数组后,只需将其写入目标工作表即可。
填充行:源数据包含宽度不一致的行,这在调用setValues()
时会出现问题,这需要将所有行平方。这将要求我们检查并填充行以避免此类错误:
范围宽度不正确,为6,但应为5(行?,文件“代码”)
填充行由push
在行数组末尾的空白“单元格”完成,直到达到预期的长度。
for (var col=mergedData[row].length; col<mergedWidth; col++)
mergedData[row].push('');
由于每一行都要处理,我们终于准备好写出结果了。
function appendUniqueRows() {
var ss = SpreadsheetApp.getActive();
var sourceSheet = ss.getSheetByName('Get Data');
var destSheet = ss.getSheetByName('Final Data');
var sourceData = sourceSheet.getDataRange().getValues();
var destData = destSheet.getDataRange().getValues();
// Check whether destination sheet is empty
if (destData.length === 1 && "" === destData[0].join('')) {
// Empty, so ignore the phantom row
destData = [];
}
// Generate hash for comparisons
var destHash = {};
destData.forEach(function(row) {
destHash[row.join('')] = true; // could be anything
});
// Concatentate source rows to dest rows if they satisfy a uniqueness filter
var mergedData = destData.concat(sourceData.filter(function (row) {
var hashedRow = row.join('');
if (!destHash.hasOwnProperty(hashedRow)) {
// This row is unique
destHash[hashedRow] = true; // Add to hash for future comparisons
return true; // filter -> true
}
return false; // not unique, filter -> false
}));
// Check whether two data sets were the same width
var sourceWidth = (sourceData.length > 0) ? sourceData[0].length : 0;
var destWidth = (destData.length > 0) ? destData[0].length : 0;
if (sourceWidth !== destWidth) {
// Pad out all columns for the new row
var mergedWidth = Math.max(sourceWidth,destWidth);
for (var row=0; row<mergedData.length; row++) {
for (var col=mergedData[row].length; col<mergedWidth; col++)
mergedData[row].push('');
}
}
// Write merged data to destination sheet
destSheet.getRange(1, 1, mergedData.length, mergedData[0].length)
.setValues(mergedData);
}