I have a script that compares values in cells in two different sheets on a google spreadsheet. It can successfully match find the matches and copy them to a 3rd sheet. However, I want to expand the selection to the column left of the matches and copy over both the matches and adjacent cells.
For clarification: Spreadsheet 1 has emails and majors, spreadsheet 2 has majors under what college they belong to. I am matching the majors so I can get the emails of only the people in a specific college. Right now all it copies are the cells with the major, but I would like it to copy the cells with the email as well (which are one column to the left).
function match_CoE() {
//Set variables for active spreadsheet, input data, comparitive data, and finalized match input.
var sh = SpreadsheetApp.getActive();
var input = sh.getSheetByName('AOP 2018-2019').getRange("C1:C").getValues();
var values = sh.getSheetByName('Major-College-Conversion').getRange("A72:A75").getValues();
var output = sh.getSheetByName('College of Education Contacts');
var match = [];
//Compare Input to Pre-determined values for matches
for (i in input){
var setInput = input[i][0];
var exists = false;
for (j in values){
var setValues = values[j][0];
if (setValues == setInput){
exists = true;
break;
}
} // end for j
if (exists == true){
match.push([setInput])
}
}//end for i
//Copy matching values to new sheet.
output.getRange(1, 1, match.length, 1).setValues(match);
}
I expanded my search range to include the email list and shifted the set data I was matching against over a row. Then changed the setInput variable in the loop to +1 narrowing the search to just the majors and adding a second variable (setInputFina) to return just the emails I was able to generate the list!
function match_CoE() {
//Set variables for active spreadsheet, input data, comparitive data, and finalized match input.
var sh = SpreadsheetApp.getActive();
var input = sh.getSheetByName('AOP 2018-2019').getRange("B1:C").getValues();
var values = sh.getSheetByName('Major-College-Conversion').getRange("A72:B75").getValues();
var output = sh.getSheetByName('College of Education Contacts');
var match = [];
//Compare Input to Pre-determined values for matches
for (i in input){
var setInput = input[i][+1];
var setInputFinal = input[i][0];
var exists = false;
for (j in values){
var setValues = values[j][+1];
if (setValues == setInput){
exists = true;
break;
}
} // end for j
if (exists == true){
match.push([setInputFinal])
}
}//end for i
//Copy matching values to new sheet.
output.getRange(1, 1, match.length, 1).setValues(match);
}
function copySet_CoE() {
}
Related
I am copying data from a spreadsheet titled after the specific month and placing it in my main spreadsheet. I have successfully copied the data into range K80:K94 on my Daily Hub sheet.
In range K80:K94 I now want to add a checkbox in column M if there is a value in column K. For example if there is a value in K80 and K81 there would be a checkbox in M80 and M81. I feel like this should be fairly straightforward, however I have tried a few different options including using IsBlank() and nothing seems to be working.
function dailyhubhabits() {
var montha = new Array(12);
montha[0] = "JANUARY";
montha[1] = "FEBRUARY";
montha[2] = "MARCH";
montha[3] = "APRIL";
montha[4] = "MAY";
montha[5] = "JUNE";
montha[6] = "JULY";
montha[7] = "AUGUST";
montha[8] = "SEPTEMBER";
montha[9] = "OCTOBER";
montha[10] = "NOVEMBER";
montha[11] = "DECEMBER";
var dailyhabitshubmonth = new Date();
var getdhmonth = montha[dailyhabitshubmonth.getMonth()];
Logger.log(getdhmonth);
var mhs = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(getdhmonth);
var monthhabitsogdata = mhs.getRange("C56:E70");
var gethabits = monthhabitsogdata.getValues();
Logger.log(gethabits);
var dhs = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("DAILY HUB");
var habitsarea = dhs.getRange("K80:K94");
monthhabitsogdata.copyTo(habitsarea);
//THIS IS WHERE I AM HAVING TROUBLE
var datavalues = dhs.getRange("K80:K94").getValues();
var data_leng = datavalues.length;
for(var i=0; i<data_leng; i++) {
if(datavalues[i][0].length != 0) {
dhs.getRange(i+1,14).insertCheckboxes();
}
}
}
You want to insert a checkbox on Column M when there is a value in the same row of column K.
There are two problems with this part of your script:
evaluating whether the cell has a value
defining the target range for the checkbox
Does the cell have a value?
length returns the number of records in an array, but it is not a good method for determining whether a cell contains a value. This is a popular topic; you might care to read Google Spreadheets Scripts: check if cell is empty for several methods.
a better approach is !== ""
Defining the target cell
dhs.getRange(i+1,14).insertCheckboxes(); - there are two problems here
Column M is 13
i starts at zero, so the first range value would be .getRange(1,14) = Cell N1.
so you need a variable that defines the startRow, such as:
var startRow = 80
REPLACE
//THIS IS WHERE I AM HAVING TROUBLE
var datavalues = dhs.getRange("K80:K94").getValues();
var data_leng = datavalues.length;
for(var i=0; i<data_leng; i++) {
if(datavalues[i][0].length != 0) {
dhs.getRange(i+1,14).insertCheckboxes();
}
}
WITH
var startRow = 80
var endRow = 94
var datavalues = dhs.getRange("K"+startRow+":K"+endRow).getValues()
var data_leng = datavalues.length;
for(var i=0; i<data_leng; i++) {
if(datavalues[i][0] !=="") {
dhs.getRange(i+startRow,13).insertCheckboxes()
}
}
SUGGESTION
In my understanding, here's your goal:
Check values in K80:K94
Insert a checkbox on a row in M that is adjacent to a row that isn't empty in the K80:K94 range.
Perhaps you could try this sample script to replace your current line on the section in inserting the check-boxes:
/** SUGGESTION
* 1. Iterate through the values in range K80:K94 & identify which aren't empty.
* 2. Get each non-empty values' row numbers.
* 3. To reduce runtime execution in the loop, if there are consecutive non-empty values, set them as a range (e.g. M80:M81). Otherwise a single value will be set as a single range (e.g. M83);
* 4. Iterate through these ranges & insert the checkboxes.
*/
var range = SpreadsheetApp.getActive().getRange('K80:K94');
var temp_values = range.getValues().map((x, i) => x != '' ? [x, (range.getLastRow() - (range.getNumRows() - i) + 1)].flat() : '*');
var ranges = temp_values.join().split('*').map(y => (y.replace(/[a-zA-Z,]+/g, '-')).split('-').filter(x => x != ''));
ranges.map(z => [...new Set([z[0], z[z.length - 1]])]).forEach(
row => row.length > 1 ? SpreadsheetApp.getActive().getRange(`M${row[0]}:M${row[1]}`).insertCheckboxes() :
SpreadsheetApp.getActive().getRange(`M${row[0]}`).insertCheckboxes()
);
/** End */
This sample script runs faster vs your current implementation as it shortens the data to be processed in the loop
Demo
Sample sheet
After running the script
Please help me out with this script that I found?
I'm not an experienced coder, so I'm just winging it at this point.
I want to simply make the process of adding check boxes to each new row automated with the following script:
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); //change this to the name of your sheet
ui = SpreadsheetApp.getUi();
//PICK ONE & comment out the other one:
var names = ss.getRange("Ranger");//Use this if you are naming the range (Refer Range)
//var names = ss.getRange("B3:B");//Use this if you are naming the ranges
var namesValues = names.getValues(); //Get array of all the names
//PICK ONE & comment out the other one:
var checkboxes = ss.getRange("Checkboxes"); //Use this if you are naming the range
//var checkboxes = ss.getRange("C2:E2"); //Use this if you want to hard-code your range
var cbRows = checkboxes.getHeight(); //Get # of rows in the ranges
var cbValues = checkboxes.getValues(); //Get array of all the checkbox column cell values
//Logger.log(cbValues);
var newCBValues = new Array(cbRows); //Create an array to store all the new checkboxes values before we edit the actual spreadsheet
for (var row = 0; row < cbRows; row++) {
newCBValues[row] = new Array(0); // Make the array 2 dimensional (even though it only has 1 column, it must be 2D).
if (namesValues[row] == "" || namesValues[row] == " ") { //If the name cell of this row is empty or blank then...
newCBValues[row][0] = " "; //Set the value to one space (which will make the cell NOT true or false, and thus NOT display a checkbox).
//Logger.log("newCBValues[" + row + "][0]: " + newCBValues[row][0]);
}else{ //otherwise, if the name cell isn't blank...
if (cbValues[row][0] === true) {
newCBValues[row][0] = true; //Keep the checkbox checked if it's already checked
}else{ //If the name cell isn't blank, and it's not true...
newCBValues[row][0] = false; //Then Keep it or set it to False (an empty checkbox):
}
}
}
checkboxes.setValues(newCBValues); // now that we have a completed array of our new checkbox values, let's edit the sheet with them!
}
I'm only able to add check boxes into one column, I would like to add check boxes into like 10 separate columns based on the value of 1 Row's cell values.Spreadsheet I'm working on to capture data
You use [row][0] which refers to the 1st column of a range
If you want to perform an an action for all columns, you need to loop through those columns.
Sample:
if (cbValues[row][0] == true) {
for( var j = 0; j < newCBValues.length; j++){
newCBValues[row][j] = true;
}
}
Btw., see here how to build checkboxes instead of copying them.
I need to add Data Validation to a range of cells based on the State chosen in the previous cell.
I've run this code which works ok for a limited amount of data but is not working on the actual spreadsheet.
function onEdit(e) { // Runs automatically when the user edits the sheet
var value = e.value; // Get the new value entered into the edited cell
var col = e.range.getColumn(); // Get the column number of the edited cell
var row = e.range.getRow(); // Get the row number of the edited cell
if (col == 6 && row >= 10 && row <= 854) { // Make sure that the edited cell is part of the table
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Hoja 1');
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Localidades'); // Get the sheet that has the table with the list of cities
var dropdownData = sheet2.getRange("A1:X594").getValues(); // Get the table with the list of cities.
var listOfCountries = dropdownData[0]; // The top row is the list of countries
var countryColumn = listOfCountries.indexOf(value); // Find the column in which the country name appears
if (countryColumn != -1) { // If the new country name is in the list
var cityList = [];
for (var dataRow = 1; dataRow < dropdownData.length; dataRow++) {
cityList.push(dropdownData[dataRow][countryColumn]);
}
var cityCell = sheet.getRange(row, col + 1);
cityCell
.clearDataValidations() // Remove any existing data validation in the target cell
.clearContent(); // Clear the cell
var rule = SpreadsheetApp.newDataValidation().requireValueInList(cityList, true).build();
cityCell.setDataValidation(rule);
}
}
}
I've debugged and it gets the CityList all right so don't know what's the problem really. Any help??
There is a limited amount of allowed dropdown options
Through testing you can easily verify that it is 500 options.
So, if you hardcode "A1:X594" you are above the limit.
However, for most of the provinces in your data the amount of options is less than 594 and your array contains many empty values.
You can remove all duplicates inlcuding emoty values by filtering, e.g.
cityList = cityList.filter(function (value, index, self) {
return self.indexOf(value) === index;
})
As for the provinces where you have many entries (e.g. Buenos Aires), maybe you can try to subdivide it into smaller regions so you have less than 500 dropdown options per dropdown?
I'm having difficulties writing the IF statement to satisfy my condition. I have 2 sheets: Main and Logistics. The first one has specific information about cargo and it's transportation, such as trailer, position and arrival date. The second sheet contains all of the transportation information, such names of the trailer, drivers, arrivals, departures etc. Based on the scheduled trailers on sheet "Logistics", the user can specify which of the available trailers he wants to use for the cargo in question.
However, in a situation when the trailer gets deleted from "Logistics" due to a cancellation, I am unable to revoke previously made selection on "Main". My idea is to make this script look for matching combinations of Destination and Trailer on both sheets (columns 8 and 13 on Main, columns 1 and 2 on Logistics). If there is a row on "Main" for which no matching trailer with the same destination was found on "Logistics", the script should set columns 13, 14 and 16 on "Main" to empty.
Could someone help me write an IF statement to satisfy this condition?
I have attached the bit of code I have so far. I think only IF statement needs modifying. Thanks for the help!
function deleteSelection() {
// Main variables:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetMain = ss.getSheetByName("Main");
var tabMain = sheetMain.getRange(2, 1, sheetMain.getLastRow(), 18);
var dataMain = tabMain.getValues();
// Logistics variables:
var sheet = ss.getSheetByName("Logistics");
var dataRange = sheet.getRange(2, 1, sheet.getLastRow(), 9);
var data = dataRange.getValues();
for(var i = 0; i < dataMain.length; i++){
for(var j = 0; j < data.length; j++){
// Compare data: if there is no match between 2 sheets, set "Trailer", "Position" and "Arrival date" to empty:
if(dataMain[i][7].toLowerCase() == data[j][0].toLowerCase() && dataMain[i][12] == data[j][1]){
} else{
dataMain[i][12] = "";
dataMain[i][13] = "";
dataMain[i][15] = "";
}
}
}
// Take the modified tab and put it on the spreadsheet
tabMain.setValues(dataMain);
}
UPD: Added a sample link. On "Logistics" you can see crossed out row, upon delete of which, a script should delete crossed out rows on "Main".
You are trying to establish whether the Event and Trailer values on Main match a value on Logistics.
I have taken a slightly different approach to you. I concatenated the value of the Main "EVent" and "Trailer" and used that value to find the match on Logistics.
If a Match is found, then the script can break out of that loop and proceed to the next loop.
If no Match is found, then a variable is incremented (since the match may be found in a subsequent comparison). However, once all the values on Logistics have been evaluated, if the number of mismatches is equal to the number of records on Logistics, then the values on Main must be updated.
function so5992862301() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetMain = ss.getSheetByName("Main");
var tabMain = sheetMain.getRange(2, 1, sheetMain.getLastRow()-1, 18);
var dataMain = tabMain.getValues();
// Logger.log("DEBUG: Last row = "+sheetMain.getLastRow()+", length of dataMain = "+dataMain.length+" tab main = "+tabMain.getA1Notation());
// Logistics variables:
var sheet = ss.getSheetByName("Logistics");
var dataRange = sheet.getRange(2, 1, sheet.getLastRow()-1, 9);
var data = dataRange.getValues();
// Logger.log("DEBUG: Logistics Last row = "+sheet.getLastRow()+", length of data = "+data.length+" dataRange = "+dataRange.getA1Notation());
// start loop through Main
for(var i = 0; i < dataMain.length; i++){
// count the matches
var mismatch=0
// start loop through Logistics
for(var j = 0; j < data.length; j++){
// match Logistics: Event (Column A) and Trailer (Column B)
// match Main: Event (Column A) and Trailer (Column C)
// Compare data: if there is no match between 2 sheets, set "Trailer", "Position" and "Arrival date" to empty:
var logEventTrailer = data[j][0]+data[j][1];
var mainEventTrailer = dataMain[i][0]+dataMain[i][2];
//Logger.log("DEBUG: i:"+i+", Main:"+mainEventTrailer+", j:"+j+" Log:"+logEventTrailer);
if (mainEventTrailer === logEventTrailer){
// match
// Logger.log("DEBUG: Match-"+"i:"+i+", Main:"+mainEventTrailer+", j:"+j+" Log:"+logEventTrailer);
// if this is a match, then break loop and goto to next i
break;
}
else{
// no match
mismatch = mismatch+1
//Logger.log("DEBUG: No match:"+match+"-i:"+i+", Main:"+mainEventTrailer+", j:"+j+" Log:"+logEventTrailer)
}
// how many mismatches
if (mismatch ==data.length){
// no match found
//Logger.log("DEBUG: no match found");
// update array values for this row
dataMain[i][2] = "";
dataMain[i][3] = "";
dataMain[i][4] = "";
}
}
}
// update the array values for Main
tabMain.setValues(dataMain);
}
I wrote a macro that creates sheet tabs and populates them based on specific criteria. For example, if I want to isolate rows indicating Closed Won, and move them to a new tab. I will run this function on my main tab called 'data' and create a new tab called 'Closed Won'.
This new tab will duplicate the same header as in 'data', and then it will populate with all rows with "Closed Won" in column L.
However, this new tab has more data than I need. I want to delete specific columns IF they have a column name AND tab name (so it does not delete the columns in my original data tab).
I am having trouble with the IF. Can someone help with a simple script that I can add to the end of the original function?
function closed_won() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('1:1').activate();
spreadsheet.insertSheet(1);
spreadsheet.getRange('1:1').activate();
spreadsheet.getActiveSheet().setName('closed_won');
spreadsheet.getRange('data!1:1').copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('data');
var testrange = sheet.getRange('L:L');
var testvalue = (testrange.getValues());
var csh = ss.getSheetByName('closed_won');
var data = [];
var j =[];
for (i=0; i<testvalue.length;i++) {
if ( testvalue[i] == 'Closed Won') {
data.push.apply(data,sheet.getRange(i+1,1,1,25).getValues());
j.push(i);
}
}
csh.getRange(csh.getLastRow()+1,1,data.length,data[0].length).setValues(data);
// THIS IS WHERE I WANT TO ADD THE DELETE COLUMN CODE
}
You want to delete columns where the header name matches a sheet name - though obviously not on the current sheet.
The process is:
get the sheets and their names; save them in an array
get the header row. This will be a 2D array, so "flatten" it to 1D for easier matching
loop through the headers and look for a match with sheet names. The code uses indexOf for this.
3.1 when you find a match of header name and column name, make sure that its not the match for the current sheet
3.2. create an array of the column numbers to be deleted.
After the loop, reverse the order of the array so that the "highest" to-be-deleted column numbers are listed first.
Loop through the to-be-deleted column numbers, and delete the columns
function SO5819343001() {
var spreadsheet = SpreadsheetApp.getActive();
// get sheets names
var thesheets = [];
var sheets = spreadsheet.getSheets();
if (sheets.length > 1) {
for (var i=0; i<sheets.length;i++){
thesheets.push(sheets[i].getName());
}
}
// move to 'closed_won'
var csh = spreadsheet.getSheetByName('closed_won');
// get the headers
//last column for range
var cshLC = csh.getLastColumn();
var headers = csh.getRange(1,1,1,cshLC).getValues();
// flatten headers from 2D to 1D
var flatheaders = headers.reduce(function(a, b){return a.concat(b);});
// Logger.log(flatheaders); DEBUG
// create variables for loop
var cshname = csh.getName();
var deletions = [];
// loop through the headers and compare to sheet names
for (var h = 0; h<cshLC;h++){
var idx = thesheets.indexOf(flatheaders[h]);
// Logger.log("DEBUG: h = "+h+", header = "+flatheaders[h]+", match = "+idx)
// is this a match?
if (idx !=-1){
// found a match for column name and sheet name
// make sure it is not this sheet
if (flatheaders[h] != cshname){
// Logger.log("DEBUG: the match is NOT on this sheet. Proceeding")
// create an array of the column numbers to be deleted
deletions.push(h+1);
}
else{
Logger.log("the match IS on this sheet. Abort.")
}
}
}
// Logger.log(deletions); DEBUG
// reverse the column order
var rev_deletions = deletions.reverse();
// Logger.log(rev_deletions); // DEBUG
// loop through the 'to-be-deleted' columns and delete them
for (d = 0;d<deletions.length;d++){
csh.deleteColumn(rev_deletions[d]);
}
}