我需要使用Apps Script根据合并的标头将列数据转置为行。 下面是我的输入和预期输出的视图,
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getRange("A1:AO1");
var mergedValues = [];
//get the header added to the array
mergedValues.push(sheet.getRange("A2:I2").getValues());
Logger.log(mergedValues);
var mergedRanges = range.getMergedRanges();
for (var i = 0; i < mergedRanges.length; i++) {
var calcA1Notation = "A"+(i+3) + ":C"+(i+3);
var monA1Notation = "D"+(i+3) + ":F"+(i+3);
//Load the Transpose values into the array
mergedValues.push([[
sheet.getRange(calcA1Notation).getValues().toString(),
mergedRanges[i].getDisplayValue(),
sheet.getRange(monA1Notation).getValues().toString()
]]);
}
Logger.log(mergedValues[0].length);
for (var i = 0; i < mergedValues.length; i++){
//Writes to the lastrow+1 of the sheet
sheet.getRange(sheet.getLastRow()+1, 1).setValue(mergedValues[i]);
}
}
你们能帮我修改Google脚本以产生预期的结果吗?
答案 0 :(得分:0)
问题中包含“移调”一词,但这具有误导性。
发问者的目标是直截了当的;将单元格从一张复制到另一张。附带一个条件,将一张表中的列标题作为单元格包含在目标范围内。
发问者演示了代码,尽管他们没有解释这在什么程度上是有目的的。该代码接收三列数据,并将值连接到单个单元格中。充其量,您可能会将此视为早期草案。
对源数据的引用并不复杂;获得月份名称是主要的麻烦。我使用两个循环遍历“源”表上的行,因为发问者的预期结果是数据应按月排序。
我本可以构建一个例程来将月份字符串值转换为数字值,然后对该值进行排序(我当然考虑过)-但我没有;)
月份名称以大写字母表示,发问者的结果使用TitleCase。同样,我可以构建一个例程来转换大小写,并且确实花了一些时间进行尝试。但是最后我决定这不是一个高度优先的事情。
function so5273586002() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
// Declare the two sheets
var sourcesheet = ss.getSheetByName("Input");
var targetsheet = ss.getSheetByName("Output");
// Get the respective starting row and ending rows.'' the target last row is declared in the loop.
var sourcestartrow = 3;
var targetstartrow = 2;
var sourcelastrow = sourcesheet.getLastRow();
// get the the data
var sourcerange = sourcesheet.getDataRange();
var sourcevalues = sourcerange.getValues();
// rubric for copying data.
// each row of the source must create two rows in the target - one row for each month
// the first three columns are repeats on both rows
// each row includes the source data as well as the month name
// target row #1
// source columns A, B & C to target A,B,C
// Month#1; value in D1 Source=> Target Column D (4)
// source columns DEF to target E F G
// target row #2
// source columns A, B & C to target A,B,C
// Month#2: value in G1 Source=> Target D (4)
// source fields G, H I to target E F G
// the questioner's prefered layout is that all the rows are sorted by month; to achive this, I used two loops
// the first to do the first month; the second to do the second month
for (i = sourcestartrow; i < (sourcelastrow + 1); i++) {
// get the last row for the target
var targetlastrow = targetsheet.getLastRow();
// Columns A, B and C -> Columns A, B and C
var targetRange = targetsheet.getRange(targetlastrow + 1, 1); //target: column =A, row = lastrow plus one
var sourcetest = sourcesheet.getRange(i, 1, 1, 3).copyTo(targetRange); // range = active row, column=A, 1 row, 3 columns, copy to SheetTracker
//Logger.log("source range is "+sourcesheet.getRange(i, 1, 1, 3).getA1Notation()+", target range is "+targetsheet.getRange(targetlastrow + 1, 1).getA1Notation());//DEBUG
// Month Name from the header
var targetRange = targetsheet.getRange(targetlastrow + 1, 4); //target: column =D, (month) row = lastrow plus one
var sourcetest = sourcesheet.getRange(1, 4).copyTo(targetRange, {
contentsOnly: true
}); // range = active row, column=A, 1 row, 3 columns, copy to SheetTracker
// Logger.log("source range is "+sourcesheet.getRange(1, 4).getA1Notation()+", target range is "+targetsheet.getRange(targetlastrow + 1, 4).getA1Notation());//DEBUG
// Month details
// Columns D E and F -> Columns E F and G
var targetRange = targetsheet.getRange(targetlastrow + 1, 5); //target: column =E, row = lastrow plus one
var sourcetest = sourcesheet.getRange(i, 4, 1, 3).copyTo(targetRange, {
contentsOnly: true
}); // range = active row, column=D(4), 1 row, 3 columns, copy to SheetTracker
// Logger.log("source range is "+sourcesheet.getRange(i, 4, 1, 3).getA1Notation()+", target range is "+targetsheet.getRange(targetlastrow + 1, 5).getA1Notation());//DEBUG
} // end loop#1
//Loop#2 to generate rows for the second month
for (i = sourcestartrow; i < (sourcelastrow + 1); i++) {
// get the last row for the target
var targetlastrow = targetsheet.getLastRow();
// Columns A, B and C -> Columns A, B and C
var targetRange = targetsheet.getRange(targetlastrow + 1, 1); //target: column =A, row = lastrow plus one
var sourcetest = sourcesheet.getRange(i, 1, 1, 3).copyTo(targetRange); // range = active row, column=A, 1 row, 3 columns, copy to SheetTracker
//Logger.log("source range is "+sourcesheet.getRange(i, 1, 1, 3).getA1Notation()+", target range is "+targetsheet.getRange(targetlastrow + 1, 1).getA1Notation());//DEBUG
// Month Name from the header
var targetRange = targetsheet.getRange(targetlastrow + 1, 4); //target: column =D, (month) row = lastrow plus one
var sourcetest = sourcesheet.getRange(1, 7).copyTo(targetRange, {
contentsOnly: true
}); // range = active row, column=G, 1 row, 3 columns, copy to SheetTracker
//Logger.log("source range is "+sourcesheet.getRange(1, 7).getA1Notation()+", target range is "+targetsheet.getRange(targetlastrow + 1, 4).getA1Notation());//DEBUG
// Month details
// Columns G H and I -> Columns E F and G
var targetRange = targetsheet.getRange(targetlastrow + 1, 5); //target: column =E, row = lastrow plus one
var sourcetest = sourcesheet.getRange(i, 7, 1, 3).copyTo(targetRange, {
contentsOnly: true
}); // range = active row, column=D(4), 1 row, 3 columns, copy to SheetTracker
// Logger.log("source range is "+sourcesheet.getRange(i, 7, 1, 3).getA1Notation()+", target range is "+targetsheet.getRange(targetlastrow + 1, 5).getA1Notation());//DEBUG
} // end loop#2
}
如我的评论所述,早期的草案缺少两点:
1)它效率低下并且遵循不良做法,因为它在创建每个字段时都会记录其值。更合适的方法是将数据写入数组,然后在逐行处理完成后将数组复制到目标范围。
2)该代码由两个循环组成,以适应演示数据中的2个月。但是,这是不切实际的结果,因为实际上每一行中可能会有任意数量的几个月的数据。再次,这是一种糟糕的做法,当时更合适的方法是假设任意数量的月数据。更为有效的方法是在遍历每一行时构建数据数组。
此修订版克服了两个缺点。
另外,由于月份名称没有按照任何有意义的顺序排序,因此我添加了一个数字月份ID,可用于在输出数据表中进行过滤和排序。
function so5273586003() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
// Declare the two sheets
var sourcesheet = ss.getSheetByName("Input");
var targetsheet = ss.getSheetByName("Output");
// Get the respective starting row and ending rows.'' the target last row is declared in the loop.
var targetstartrow = 2;
var sourcestartrow = 2;
var sourcelastrow = sourcesheet.getLastRow();
var sourcelastcolumn = sourcesheet.getLastColumn();
//Logger.log("the last row is "+sourcelastow+", and the last column is "+sourcelastcolumn);
// get the the data
var sourcerange = sourcesheet.getDataRange();
var sourcevalues = sourcerange.getValues();
var sourcelength = sourcevalues.length;
var i = 0;
var m = 0;
var month = 1;
var dataarray = [];
var masterarray = [];
// start loop by row
for (i = sourcestartrow; i < (sourcelastrow); i++) {
// start loop by month (within row)
for (m = 0; m <= (sourcelastcolumn - 6); m = m + 3) {
dataarray = [];
// add first three columns
dataarray.push(sourcevalues[i][0]);
dataarray.push(sourcevalues[i][1]);
dataarray.push(sourcevalues[i][2]);
//add the month name
dataarray.push(sourcevalues[0][3 + m]);
//add month data
dataarray.push(sourcevalues[i][3 + m]);
dataarray.push(sourcevalues[i][4 + m]);
dataarray.push(sourcevalues[i][5 + m]);
//create month id
switch (sourcevalues[0][3 + m]) {
case "JULY":
month = 1;
break;
case "AUGUST":
month = 2;
break;
case "SEPTEMBER":
month = 3;
break;
case "OCTOBER":
month = 4;
break;
case "NOVEMBER":
month = 5;
break;
case "DECEMBER":
month = 6;
break;
case "JANUARY":
month = 7;
break;
case "FEBRUARY":
month = 8;
break;
case "MARCH":
month = 9;
break;
case "APRIL":
month = 10;
break;
case "MAY":
month = 11;
break;
case "JUNE":
month = 12;
break;
default:
month = 100;
break;
} // end switch
// add the month id to the array (used for sorting)
dataarray.push(month);
// add the data to the master array before zeroing for next month
masterarray.push(dataarray);
} // months loop
} // end row loop
// get the length of the master array
var masterlength = masterarray.length;
// define the target range
var TargetRange = targetsheet.getRange(targetstartrow, 1, masterlength, 8);
// set the array values on the Target sheet
TargetRange.setValues(masterarray);
}