I am using the below code to create the validations in google sheet (contributed by Cooper), what this script does is it automatically check the applicable headers and create the dropdown with values and hide the columns which are not applicable.
I am trying to solve here is:
The script checks the applicable headers related to the Product Selection
It creates the dropdown with validation values
Instead of hiding the not applicable columns, It removes them from the sheet
I am a beginner to google script and tried using the deletecolumn function but unable to get it work.
Please help me out here.
function loadObjectsAndCreateProductDropDown() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet0');
const psh = ss.getSheetByName('Sheet1');
const [ph, ...prds] = sh.getRange(1, 1, 10, 6).getValues().filter(r => r[0]);
const [ch, ...chcs] = sh.getRange(11, 1, 10, 10).getValues().filter(r => r.join());
let pidx = {};
ph.forEach((h, i) => { pidx[h] = i });
let prd = { pA: [] };
prds.forEach(r => {
if (!prd.hasOwnProperty(r[0])) {
prd[r[0]] = { type: r[pidx['Type']], size: r[pidx['Size']], color: r[pidx['Color']], material: r[pidx['Material']], length: r[pidx['Length']] };
prd.pA.push(r[0]);
}
});
let cidx = {};
let chc = {};
ch.forEach((h, i) => { cidx[h] = i; chc[h] = [] });
chcs.forEach(r => {
r.forEach((c, i) => {
if (c && c.length > 0) chc[ch[i]].push(c)
})
})
const ps = PropertiesService.getScriptProperties();
ps.setProperty('product_matrix', JSON.stringify(prd));
ps.setProperty('product_choices', JSON.stringify(chc));
Logger.log(ps.getProperty('product_matrix'));
Logger.log(ps.getProperty('product_choices'));
psh.getRange('A2').setDataValidation(SpreadsheetApp.newDataValidation().requireValueInList(prd.pA).build());
}
//I chose to use an installable dropdown. I'm not sure if it's needed. Its up to you.
function onMyEdit(e) {
//e.source.toast('entry')
const sh = e.range.getSheet();
if (sh.getName() == 'Sheet1' && e.range.columnStart == 1 && e.range.rowStart == 2 && e.value) {
//e.source.toast('flag1');
sh.getRange('C2:G2').clearDataValidations();
let ps = PropertiesService.getScriptProperties();
let prodObj = JSON.parse(ps.getProperty('product_matrix'));//recovering objects from PropertiesService
let choiObj = JSON.parse(ps.getProperty('product_choices'));
let hA = sh.getRange(1, 1, 1, sh.getLastColumn()).getDisplayValues().flat();
let col = {};
hA.forEach((h, i) => { col[h.toLowerCase()] = i + 1 });
["type", "size", "color", "material", "length"].forEach(c => {
if (choiObj[prodObj[e.value][c]]) {
sh.getRange(e.range.rowStart, col[c]).setDataValidation(SpreadsheetApp.newDataValidation().requireValueInList(choiObj[prodObj[e.value][c]]).build()).offset(-1,0).setFontColor('#000000');
sh.showColumns(col[c])
} else {
sh.getRange(e.range.rowStart, col[c]).offset(-1,0).setFontColor('#ffffff');
sh.hideColumns(col[c]);
}
})
}
}
demo sheet
https://docs.google.com/spreadsheets/d/18guAXXjWIMDQilX8Z0Y4_Avogjs2ESMbrZY7Sb9TaxE/edit#gid=0
Sample Data
P1
Type
Size
Color
Material
Length
Kurta Pyjamas
No
Sizeethnic_1
Colorethnic_1
Materialethnic_3
Lengthethnic_1
Dhotis
Typethnic_1
No
Colorethnic_2
Materialethnic_2
No
Sherwani
No
No
Colorethnic_2
No
Lengthethnic_2
Men Pyjamas
Typeethnic_2
No
Colorethnic_2
No
No
Kurtas
No
Sizeethnic_2
Colorethnic_1
No
Lengthethnic_1
Ethnic Jackets
No
No
Colorethnic_1
No
No
Typethnic_1
Typeethnic_2
Sizeethnic_1
Sizeethnic_2
Colorethnic_1
Colorethnic_2
Materialethnic_3
Materialethnic_2
Lengthethnic_1
Lengthethnic_2
Mundu
Churidar
XS
XS
Beige
Green
Blended
Silk Blend
Above Knee
Short
Regular Dhoti
Regular Pyjama
S
S
Black
Grey
Cotton
Velevt
Ankle Length
Medium
Patiala
M
M
Blue
Maroon
Dupion
Viscose Rayon
Jodhpuri
L
L
Brown
Multi
Wool
Harem
XL
XL
Copper
Mustard
XXL
XXL
Cream
3XL
3XL
Gold
Suggestion
This may not be the cleanest code but you may try this implementation below. Instead of removing columns, it will clear the Sheet1 headers and their corresponding drop-downs on every new selection on the A2 drop-down.
NOTE: Since your sample data will increase in size overtime, this setup will need you to put the data into a separate sheet tab for a cleaner setup, such as this sample below:
Data1 sheet tab:
Data2 sheet tab:
UPDATED
Sample Script
var sh = SpreadsheetApp.getActiveSpreadsheet();
var selection = sh.getSheetByName("Sheet1").getRange("A2").getValue(); //Get the selection on the dropdowm on cell A2
var data1 = sh.getSheetByName("Data1").getDataRange().getDisplayValues();
var data2 = sh.getSheetByName("Data2").getDataRange().getDisplayValues();
function addHeaders(sheet, values) { //Adds the headers from Column C and beyond
var startCol = 3; //Column C
var endCol = startCol + values.length;
values.forEach(x => {
if(startCol <= endCol){
if(checkHeaderIfYesOrNo(x) == true)return;
sheet.getRange(1,startCol).setValue(x);
startCol += 1;
}
});
}
function onEdit(e) {
if(e.range.getA1Notation() != "A2")return;//Make sure to run onEdit function ONLY when cell A2 is edited/selected
var headers = [];
var headerValues = [];
var temp = [];
var counter = 0;
clean();
data1 = fixDuplicates();
//find selection name on data1
for(var x = 0; x< data1.length; x++){
var name = data1[x][0];
if(name == selection){
///get the headers & their values
data1[x].forEach(res => {
if(res != "" & res != selection){
var index1 = data1[x].indexOf(res);
var index2 = data2[0].indexOf(res);
headers.push([data1[0][index1]]);
for(var y=0; y< data2.length; y++){
if(data2[y][index2] != "" && data2[y][index2] != res){
temp.push("**"+res+"**"+data2[y][index2]); //place raw header data to a temporary variable
}
}
//Set the drop-down data of each headers
temp.forEach(raw => { //clean the temp array
if(raw.includes(res)){
var regex = /\*\*([^*]*(?:\*(?!\*)[^*]*)*)\*\*/g;
headerValues.push(raw.replace(regex, ""))
}
});
//Logger.log("Data of the \""+res+"\" header:\n"+headerValues);
//set data validation per header
counter += 1;
if(res.toLowerCase().includes("no"))return; //skip creating data validation for "No" header
if(res.toLowerCase().includes("yes")) return; //skip creating data validation for "Yes" header
sh.getSheetByName("Sheet1").getRange(2,2+counter).setDataValidation(SpreadsheetApp.newDataValidation().requireValueInList(headerValues).build());
headerValues = [];
}
});
}
}
addHeaders(sh.getSheetByName("Sheet1"), headers);
}
function clean(){ //Clean Sheet 1 on every edit
sh.getSheetByName("Sheet1").getRange('C2:Z').clearDataValidations();
sh.getSheetByName("Sheet1").getRange('C1:Z').clearContent();
}
function fixDuplicates(){
var temp = [];
var data1New = [];
var count = 1;
for(var x=0; x<data1.length; x++){
data1[x].forEach(findIt => {
if(findIt.toLowerCase().includes("yes") || findIt.toLowerCase().includes("no")){
temp.push(findIt+count);
count += 1;
}else{
temp.push(findIt);
}
})
data1New.push(temp);
temp=[];
}
return data1New;
}
function checkHeaderIfYesOrNo(h){
for(var x=0; x<data1.length; x++){
if(data1[x][0] == selection){
if(data1[x][data1[0].indexOf(h.toString())].toLowerCase().includes("yes")){
Logger.log(h +" contains Yes");
return null;
}else if(data1[x][data1[0].indexOf(h.toString())].toLowerCase().includes("no")){
Logger.log(h+" header will not be added as it has \"No\" value");
return true;
}else{
Logger.log("Skip the "+h +" header");
return null;
}
}
}
}
Sample Demonstration:
Sample Execution Log result for review:
Related
I have 1 spreadsheet with multiple sheets.
The 1st and the 2nd sheets sometimes have similar data in the rows (duplicates). Also, each sheet has a column (8) with a checkbox.
Task: I need to move one of the duplicates to the 3rd sheet when the checkboxes in both sheets (1st and 2nd) are checked.
Here is the code that moves the row when it's checked in a single sheet.
Can someone help me modify it to complete my task?
function onEdit(e) {
let range = e.range;
let col = range.getColumn();
let row = range.getRow();
let val = range.getValue();
let source = e.source.getActiveSheet();
let ss = SpreadsheetApp.getActiveSpreadsheet();
let sourceSheet = ss.getSheetByName(source.getName());
if (sourceSheet.getName() == 'SHEET1' && col == 8 && val == true){
let data = sourceSheet.getRange(row,1,1,7).getValues();
let targetSheet = ss.getSheetByName('SHEET2');
targetSheet.appendRow(data[0]);
sourceSheet.deleteRow(row);
}
if (sourceSheet.getName() == 'SHEET2' && col == 8 && val == true){
let data = sourceSheet.getRange(row,1,1,7).getValues();
let targetSheet = ss.getSheetByName('SHEET3');
targetSheet.appendRow(data[0]);
sourceSheet.deleteRow(row);
}
}
Sample Spreadsheet
Apply filter()
You can add the filter() method (combined with the JSON.stringify() method) to your script to determine if a row is a duplicate of another from the other sheet. The modified script should somehow look like this:
function onEdit(e) {
var range = e.range;
var col = range.getColumn();
var row = range.getRow();
var val = range.getValue();
var source = e.source.getActiveSheet();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = ss.getSheetByName(source.getName());
var targetSheet = ss.getSheetByName('Sheet3');
//If Sheet1 checkbox is triggered
if (sourceSheet.getName() == 'Sheet1' && col == 8 && val == true) {
var rowArr = ss.getSheetByName('Sheet1').getRange(row, 1, 1, 8).getValues();
var lastRow2 = ss.getSheetByName('Sheet2').getLastRow();
var sheet2Values = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet2').getRange(1, 1, lastRow2, 8).getValues();
var count = sheet2Values.filter(x => {
return (JSON.stringify(x) === JSON.stringify(rowArr[0]))
});
var otherRow = sheet2Values.map((x, i) => {
if (JSON.stringify(x) === JSON.stringify(rowArr[0])) {
return i;
}
});
if (count.length > 0) {
var otherRow = sheet2Values.map((x, i) => {
if (JSON.stringify(x) === JSON.stringify(rowArr[0])) {
return i;
}
}).filter(y => y);
rowArr[0].pop();
targetSheet.appendRow(rowArr[0]);
sourceSheet.deleteRow(row);
var otherSheet = ss.getSheetByName('Sheet2');
otherSheet.deleteRow(otherRow[0] + 1)
}
}
//If Sheet2 checkbox is triggered
if (sourceSheet.getName() == 'Sheet2' && col == 8 && val == true) {
var rowArr = ss.getSheetByName('Sheet2').getRange(row, 1, 1, 8).getValues();
var lastRow = ss.getSheetByName('Sheet1').getLastRow();
var sheet1Values = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1').getRange(1, 1, lastRow, 8).getValues();
var count = sheet1Values.filter(x => {
return (JSON.stringify(x) === JSON.stringify(rowArr[0]))
});
if (count.length > 0) {
var otherRow = sheet1Values.map((x, i) => {
if (JSON.stringify(x) === JSON.stringify(rowArr[0])) {
return i;
}
}).filter(y => y);
rowArr[0].pop();
targetSheet.appendRow(rowArr[0]);
sourceSheet.deleteRow(row);
var otherSheet = ss.getSheetByName('Sheet1');
otherSheet.deleteRow(otherRow[0] + 1)
}
}
}
Output
Based on your sample spreadsheet, the modified script should work as shown below:
Please take note that the appendRow() method appends any row to the last non-empty row in the sheet. A row with a checkbox is not considered to be an empty row thus explains the behavior of the output.
Reference
filter()
JSON.stringify()
Would that do what you want ?
function copyDuplicateRows() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet1 = spreadsheet.getSheetByName("Sheet1");
var sheet2 = spreadsheet.getSheetByName("Sheet2");
var sheet3 = spreadsheet.getSheetByName("Sheet3"); // destination sheet
var data1 = sheet1.getDataRange().getValues();
var data2 = sheet2.getDataRange().getValues();
// Use a JavaScript object to keep track of duplicate rows
var seen = {};
// Iterate through data1 and copy unique rows to sheet3
for (var i = 0; i < data1.length; i++) {
var row = data1[i];
var key = row.join(); // create a unique key for each row
if (!seen[key]) {
seen[key] = true;
sheet3.appendRow(row);
}
}
// Iterate through data2 and copy unique rows to sheet3
for (var i = 0; i < data2.length; i++) {
var row = data2[i];
var key = row.join();
if (!seen[key]) {
seen[key] = true;
sheet3.appendRow(row);
}
}
}
I copy "range" from one sheet to another using range.copyTo(..) function, it doesnt copy group information
var destSheet = some_sheet;
var sourceRange=SpreadsheetApp.getActiveSheet().getRange("A1:H10");
sourceRange.copyTo(destSheet.getRange(1,1));
Values, format, formula are copied. Not groups
Issue and workaround:
In the current stage, it seems that the dimension groups cannot be directly copied by copyTo method. So, in order to copy the dimension groups, it is required to retrieve the dimension groups and put them.
When Sheets API is used, the dimension groups can be retrieved as an object. Using this, in this answer, I would like to propose to use Sheets API. When this is reflected in your script, it becomes as follows.
Modified script:
Before you use this script, please enable Sheets API at Advanced Google services. And, please set your destination sheet name.
function deleteDimensionGroups_(sheetId, sheet) {
var obj = [...(sheet.rowGroups || []), ...(sheet.columnGroups || [])];
if (obj.length == 0) return [];
return obj
.sort((a, b) => a.depth < b.depth ? 1 : -1)
.map(o => {
o.range.sheetId = sheetId;
delete o.depth;
return { deleteDimensionGroup: o };
});
}
// Please run this function.
function main() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssId = ss.getId();
var srcSheet = ss.getActiveSheet();
var dstSheet = ss.getSheetByName("Sheet2"); // Please set your destination sheet name.
var sourceRange = srcSheet.getRange("A1:H10");
sourceRange.copyTo(dstSheet.getRange(1, 1));
// Copy dimension groups.
var { sheets } = Sheets.Spreadsheets.get(ssId, { ranges: [srcSheet.getSheetName(), dstSheet.getSheetName()] });
var sheet = sheets[0];
var obj = [...(sheet.rowGroups || []), ...(sheet.columnGroups || [])];
if (obj.length == 0) return;
var sheetId = dstSheet.getSheetId();
var reqs = deleteDimensionGroups_(sheetId, sheets[1]);
var requests = [...reqs, ...obj
.sort((a, b) => a.depth > b.depth ? 1 : -1)
.map(o => {
o.range.sheetId = sheetId;
delete o.depth;
return { addDimensionGroup: o };
})];
Sheets.Spreadsheets.batchUpdate({ requests }, ssId);
}
Note:
In this sample script, the existing dimension groups are deleted from the destination sheet and the new dimension groups are copied. If you don't want to delete the dimension groups in the destination sheet, please modify the above script as follows.
From:
var reqs = deleteDimensionGroups_(sheetId, sheets[1]);
To:
var reqs = [];
References:
Method: spreadsheets.batchUpdate
AddDimensionGroupRequest
Added:
From your following reply,
It's full of informations. Trying to adapt it and create a copyToWithGroup(sourceRange, destRange).. not so easy at my level. But I have materials in your answer to work with.
If you want to limit the range using var sourceRange = srcSheet.getRange("A1:H10");, how about the following sample script?
Sample script:
function deleteDimensionGroups_(sheetId, obj) {
if (obj.length == 0) return [];
return obj
.sort((a, b) => a.depth < b.depth ? 1 : -1)
.map(o => {
o.range.sheetId = sheetId;
delete o.depth;
return { deleteDimensionGroup: o };
});
}
// Please run this function.
function main() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssId = ss.getId();
var srcSheet = ss.getActiveSheet();
var dstSheet = ss.getSheetByName("Sheet2"); // Please set your destination sheet name.
var sourceRange = srcSheet.getRange("A1:H10"); // In this sample, this range is used.
sourceRange.copyTo(dstSheet.getRange(1, 1));
// Copy dimension groups in "sourceRange".
var startRowIndex = sourceRange.getRow() - 1;
var endRowIndex = startRowIndex + sourceRange.getNumRows();
var startColumnIndex = sourceRange.getColumn() - 1;
var endColumnIndex = startColumnIndex + sourceRange.getNumColumns();
var { sheets: [src, dst] } = Sheets.Spreadsheets.get(ssId, { ranges: [srcSheet.getSheetName(), dstSheet.getSheetName()] });
var check = f => f.filter(({ range }) => {
if (range.dimension == "ROWS" && range.startIndex >= startRowIndex && range.endIndex <= endRowIndex) {
return true;
} else if (range.dimension == "COLUMNS" && range.startIndex >= startColumnIndex && range.endIndex <= endColumnIndex) {
return true;
} else {
return false;
}
});
var [src2, dst2] = [src || [], dst || []].map(e => {
var temp = [];
if (e.rowGroups && e.rowGroups.length > 0) temp = [...temp, ...check(e.rowGroups)];
if (e.columnGroups && e.columnGroups.length > 0) temp = [...temp, ...check(e.columnGroups)];
return temp;
});
if (src2.length == 0) return;
var sheetId = dstSheet.getSheetId();
var reqs = deleteDimensionGroups_(sheetId, dst2);
var requests = [...reqs, ...src2
.sort((a, b) => a.depth > b.depth ? 1 : -1)
.map(o => {
o.range.sheetId = sheetId;
delete o.depth;
return { addDimensionGroup: o };
})];
Sheets.Spreadsheets.batchUpdate({ requests }, ssId);
}
I want to split the google sheet into different workbooks, not tabs in the same workbook based on values in column A. Although I have got a script that splits the data into different workbooks but the data range in it is not dynamic like the number of columns to be added into each workbook are fixed. I want them to be dynamic like till the last column of the data range. I have tried a lot to make it dynamic by adding loops but it shows The number of columns in the data does not match the number of columns in the range. The data has 1 but the range has 12. this error. The data in the log has almost no difference for the fixed range (which is working fine) and for the dynamic range that I have tried to it But don't know why it is showing error. Have got stuck into it. any help will be highly appreciated.
This the function that I am trying.
function splitSheets() {
var theWorkbook = SpreadsheetApp.getActiveSpreadsheet();
var theSheet = theWorkbook.getSheetByName("Master");
var slc = theSheet.getDataRange().getLastColumn()
var slcv = theSheet.getRange("B1:B" + slc).getValues()
var sheets = theWorkbook.getSheets();
for (i = 0; i < sheets.length; i++) {
switch(sheets[i].getSheetName()) {
case "Master":
break;
default:
theWorkbook.deleteSheet(sheets[i]);
}
}
var key = theSheet.getRange("A:A").getValues();
var rows = theSheet.getDataRange().getValues();
var headerFormat = theSheet.getRange("2:2").getValues();
var folderId = '16XVypjB5_PWe2PaBIREpDGCNQlZuWL4k'
var completedSheets = [];
for (var i = 2; i < key.length; i++) {
// if(completedSheets.includes('Blank') && key[i][0] === ""){
// }else{
if(!completedSheets.includes(key[i][0]) ) {
if (key[i][0] === "") {
var name = 'Blank'
var resource = {
title: name,
mimeType: MimeType.GOOGLE_SHEETS,
parents: [{ id: folderId }]
}
var insertedFile = Drive.Files.insert(resource)
var csid = insertedFile.id
var currentSheet = SpreadsheetApp.openById(csid).getSheetByName("Sheet1")
// var currentSheet = theWorkbook.insertSheet("Blank");
} else {
var name = key[i][0]
var resource = {
title: name,
mimeType: MimeType.GOOGLE_SHEETS,
parents: [{ id: folderId }]
}
var insertedFile = Drive.Files.insert(resource)
var csid = insertedFile.id
var currentSheet = SpreadsheetApp.openById(csid).getSheetByName("Sheet1")
// var currentSheet = theWorkbook.insertSheet(key[i][0]);
}
var theNewRows =[];
var b=0;
for(var j = 1; j < rows.length; j++) {
var rown = []
for(var c = 0; c < slcv.length; c++){
// some other trials
// if((rows[j][0] == key[i][0]) || (rows[j][0] === '' && currentSheet.getName() == "Blank")){
// theNewRows[b]=[];
// theNewRows[b].push (
// rows[j][c].toString()
// This although adds the data and range dynamically but also shows the mentioned error.
rown.push(rows[j][c])
// );
// b++;
// }
}
if((rows[j][0] == key[i][0]) || (rows[j][0] === '' && currentSheet.getName() == "Blank")){
theNewRows[b]=[];
theNewRows[b].push (
rown.toLocaleString()
// These are the fixed column for data rnage
// rows[j][0],rows[j][1],rows[j][2],rows[j][3],rows[j][4],rows[j][5],rows[j][6],rows[j][7],rows[j][8],rows[j][9],rows[j][10],rows[j][11]
);
b++;
}
Logger.log(rown)
}
Logger.log(theNewRows)
// Logger.log(theNewRows)
currentSheet.getRange("1:1").setValues(headerFormat)
var outrng = currentSheet.getRange(2,1,theNewRows.length, slc);//Make the output range the same size as the output array
outrng.setValues(theNewRows);
currentSheet.autoResizeColumns(1, slc);
if(currentSheet.getSheetName() == 'Blank') {
completedSheets.push('Blank');
last = "Blank";
}else{
completedSheets.push(key[i][0])
last = key[i][0]
// }
}
}
}
SpreadsheetApp.setActiveSheet(theWorkbook.getSheetByName('Master'));
}
I overhauled and improved your script to be more readable and use a lot less Spreadsheet calls by using array methods instead.
Script:
function splitSheets() {
var folderId = '*** FOLDER ID ***';
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheets = spreadsheet.getSheets();
var sheet = spreadsheet.getSheetByName('Master');
// delete sheets that are not named 'Master'
sheets.forEach(sheetIter => {
if(sheetIter.getSheetName() != 'Master')
spreadsheet.deleteSheet(sheetIter);
});
var data = sheet.getDataRange().getValues();
// remove 1st row (blank row)
data.shift();
// remove 2nd row from data and assign as headers
var headers = data.shift();
// get unique list of sheet names from column A
var sheetNames = data.map(row => row[0]).filter(onlyUnique);
// loop those unique sheetNames
sheetNames.map(sheetName => {
// filter data by getting only rows with same column A and sheetName
var outputData = data.filter(row => row[0] == sheetName);
// add header from data filtered
outputData.unshift(headers);
var resource = {
title: sheetName || 'Blank',
mimeType: MimeType.GOOGLE_SHEETS,
parents: [{ id: folderId }]
}
var file = Drive.Files.insert(resource);
var currentSheet = SpreadsheetApp.openById(file.id).getSheetByName('Sheet1');
// write data filtered with the header
currentSheet.getRange(1, 1, outputData.length, outputData[0].length).setValues(outputData);
// resize the columns
currentSheet.autoResizeColumns(1, outputData[0].length);
});
}
// function to get unique values from array using filter
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
Sample Output:
function test() {
var ss1 = SpreadsheetApp.getActiveSpreadsheet();
var ss = ss1.getActiveSheet();
var only = ['AutoGR', 'Sheet2', 'Sheet3', 'Sheet4'];
if (only.indexOf(ss.getName()) == -1) return;
var numRows = SpreadsheetApp.getActiveSheet().getLastRow();
var range;
for (var i = 1; i <= numRows; i++) {
range = ss.getRange('B' + i);
if (range.getValues() == "Crate") {
range.offset(0, 4).setValue(3000);
}
}
for (var i = 1; i <= numRows; i++) {
range = ss.getRange('B' + i);
if (range.getValues() == "Pallet") {
range.offset(0, 4).setValue(4200);
}
}
}
What I am trying to achieve is if values in column B = ‘Crate’ then in the same row under column named Qty put value automatically as 3000, if values in column B = ‘Pallet’ then Qty column automatically gets updated as 4200 but when B=‘close operation’ I have to add qty manually.
Setting Column F in multiple sheets using getValues() and setValues()
function test() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const incl = ['AutoGR', 'Sheet2', 'Sheet3', 'Sheet4'];
const shts = ss.getSheets().filter(sh => ~incl.indexOf(sh.getName()));
shts.forEach(sh => {
let bs = sh.getRange(1,2,sh.getLastRow()).getValues();
let fs = sh.getRange(1,6,sh.getLastRow()).getValues();
bs.forEach((r,i) => {
if(r[0] == "Crate") {
fs[i][0] = 3000;
} else if(r[0] == "Pallet") {
fs[i][0] = 4200;
}
})
sh.getRange(1,6,fs.length,1).setValues(fs);
})
}
If this causes problems in other cells in F then you may be forced to write to F one cell at a time but you'll still get better performance on the read side.
I am trying to write a code that will look for a match (2 criteria) and will return a value.
Here is sample spreadsheet: Sample
What I want to achieve is:
Read Product and Stage data from the Result(段取)sheet
Find a match in DataBase sheet
Get the Time (cell next to stage) value and copy it to the Result sheet
DataBase is constant and it won't get change but the Result (product and stage) will change everyday.
Please think of it as of production process. In database you have written whole process and in the Result sheet you have current status of the production. I want to know how much time left to get final product and also I want to know time of every stage.
In the spreadsheet you have ExampleResult which is showing the result I want to achieve.
So I guess it has to be something which will look for a match first in Column (for a product) and then in a Row (for a stage). Original data has around 40 columns and 15000 rows...
Do you have any idea how it can be solved?
This is function I wrote so far but don't know how to move it further...
function findmatch(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var srcSheet = ss.getSheetByName("DataBase(段取)");
var srcValues = srcSheet.getRange(2, 1, srcSheet.getLastRow(), srcSheet.getLastColumn()).getValues();
var productlist = srcValues.map(function(r){return r[0]});
var stage = srcValues.map(function(r){return r[2]});
var arr1 = Array.of(productlist);
var arr2 = Array.of(stage);
var position = arr1.indexOf(productlist);
if (position >-1){
return arr2[position];
}else {
return 'N/A';
}
Logger.log(srcValues)
}
and this:
function match(){
const ss = SpreadsheetApp.getActiveSpreadsheet();
var srcSheet = ss.getSheetByName("ルーチンデータ(加工)");
var srcValues = srcSheet.getRange(2, 1, srcSheet.getLastRow()-1, srcSheet.getLastColumn()).getValues();
var lol = Array.of(srcValues);
var filtered = lol.filter(item => item);
const dstSheet = ss.getSheetByName("結果(段取)");
const dstValues = dstSheet.getRange(2, 1, dstSheet.getLastRow()-1, dstSheet.getLastColumn()).getValues();
var loldst = Array.of(dstValues);
var filtered1 = loldst.filter(item => item);
let map = {};
filtered.forEach(i => map[i] = false);
filtered1.forEach(i => map[i] === false && (map[i] = true));
let jsonArray = Object.keys(map).map(k => ({ name: k, matched: map[k] }));
Logger.log(jsonArray);
}
I will be very grateful for any advice.
Regards,
Pimo
So I found a solution to my problem.
Maybe it will be helpful for other as well
function makeArray(srcValues){
const maxSrcValues = srcValues.length;
const srcAry = [];
for(let i = 0; i< maxSrcValues; i++){
let maxCol = srcValues[i].length;
let rowAry = [];
for(let j = 2; j<maxCol; j = j+2 ){
if(srcValues[i][j]){
let t = 0
if(srcValues[i][j + 1]){
t = parseFloat(srcValues[i][j + 1]);
}
rowAry.push({'stage': srcValues[i][j], 'time': t});
}
}
srcAry.push({'product': srcValues[i][0], 'stages': rowAry});
}
return srcAry;
}
function getTime(product, stage, srcAry){
const maxSrcAry = srcAry.length;
for(let i= 0; i<maxSrcAry; i++ ){
if(product == srcAry[i].product){
let maxRow = srcAry[i].stages.length;
for(let j=0; j<maxRow;j++){
if(stage == srcAry[i].stages[j].stage){
return parseFloat(srcAry[i].stages[j].time);
}
}
}
}
return 0;
}
function getDbProductByStages(product, stagesList,srcAry){
if(stagesList === null){
return false;
}
const maxSrcAry = srcAry.length;
const firstKey = stagesList[0].stage;
let stagesCnt = 0
for(let i= 0; i<maxSrcAry; i++ ){
if(product == srcAry[i].product){
stagesCnt = srcAry[i].stages.length
for(let j=0; j<stagesCnt;j++){
if(firstKey == srcAry[i].stages[j].stage){
if(isSameProduct(j, srcAry[i].stages, stagesList) === true){
return srcAry[i].stages;
}
}
}
}
}
return false;
}
function isSameProduct(idx, srcStages, destStages) {
const maxDstStg = destStages.length - 1;
const maxSrcStg = srcStages.length - idx;
if(maxDstStg > maxSrcStg){
return false;
}
for(let i = 0; i<maxDstStg; i++){
if(destStages[i].stage != srcStages[i + idx].stage){
return false;
}
}
return true;
}
function getStageTime(firstStg, idx, stage, dbProduct){
const maxCnt = dbProduct.length
for(let i = 0; i < maxCnt; i++){
if(firstStg == dbProduct[i].stage){
if(dbProduct[i + idx] && dbProduct[i + idx].stage == stage){
return dbProduct[i + idx].time;
}
break;
}
}
return 0;
}
function doProcess() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
// 1. Retrieve the source values from database sheet.
const srcSheet = ss.getSheetByName("DataBase(段取)");
const srcValues = srcSheet.getRange(2, 1, srcSheet.getLastRow(), srcSheet.getLastColumn()).getValues();
const srcAry = makeArray(srcValues);
// 3. Retrieve the source values from Report sheet.
const dstSheet = ss.getSheetByName("Result(段取)");
const dstValues = dstSheet.getRange(2, 1, dstSheet.getLastRow() - 1, dstSheet.getLastColumn()).getValues();
// 4. Create an array for putting to Spreadsheet using the created object.
const destAry = makeArray(dstValues);
const maxDestAry = destAry.length;
const result = [];
for(let i= 0; i<maxDestAry; i++ ){
let row = [];
let rowPartial = [];
row.push(destAry[i].product);
let timeLeft = 0;
let timeTmp = 0;
let maxRow = destAry[i].stages.length;
let dbProduct = getDbProductByStages(destAry[i].product, destAry[i].stages,srcAry);
for(let j=0; j<maxRow;j++){
rowPartial.push(destAry[i].stages[j].stage);
if(dbProduct){
timeTmp = getStageTime(destAry[i].stages[0].stage,j,destAry[i].stages[j].stage, dbProduct);
}else{
timeTmp = 0;
}
rowPartial.push(timeTmp);
timeLeft = timeLeft + timeTmp;
}
row.push(timeLeft);
for(let k=0;k<rowPartial.length;k++) {
row.push(rowPartial[k]);
}
result.push(row);
}
const maxLength = result.length;
let maxColl = 0;
for(let i=0; i<maxLength;i++){
if(maxColl < result[i].length){
maxColl = result[i].length;
}
}
for(let i=0; i<maxLength;i++){
if(result[i].length < maxColl){
let diff = maxColl - result[i].length;
for(let j=0;j<diff;j++){
result[i].push('');
}
}
}
const wynikSheet = ss.getSheetByName("wynik");
wynikSheet.getRange(2,1, result.length, result[0].length).setValues(result);
}
Just run the doProcess function