Description:
Stack Overflow user mhawksey recently did some fantastic optimization of my code, and in doing so, introduced me to super efficient array pushes. But working with arrays is kind of difficult, because I can't seem to be able to use functions I can when using the traditional .getRange/.setValue approach.
Problem:
I need to integrate .setFontColors('red') and .setBackgroundColors('white').
Code and Images:
First, I will post the code. Second, an image of what the currently code does. Third, an image of what the code needs to do.
function format() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getActiveSheet();
var lastRow = s.getLastRow();
var row;
//gets a [][] of all values in the column
var data = s.getRange("A:A").getValues();
//we are going to build a [][] to output result
var output = [];
//loop through all cells in column A
for (row = 0; row < lastRow; row++) {
var cellValue = data[row][0];
var dash = false;
if (typeof cellValue === 'string') {
dash = cellValue.substring(0, 1);
//if a number copy to our output array
} else {
output.push([cellValue]);
}
//if -dash
if (dash === "-") {
//build first + last name
var name = (data[(row+1)][0]+" "+data[(row+2)][0]).trim();
//add row for the -state (e.g. -MI)
output.push([cellValue]);
output.push([name]);
output.push(["Order complete"]);
//add a blank row
output.push([""]);
//jump an extra row to speed things up
row++;
}
}
//set the values we've made in our output [][] array
s.getRange(1, 1, output.length).setValues(output);
}
This is what the code does:
This is what I'm trying to achieve:
Update:
I've appended a simple, working formatting loop. The problem is, when I run it on a longer column of data, it takes too long to process. From what I understand of the comments, I cannot quickly format a spreadsheet. Am I wrong?
Appended formatting code:
//other variables
var range1;
//loop through column A
for (var row = 0; row < lastRow; row++) {
range1 = s.getRange(row + 1, 1);
//define offsets for if statement
var offset1 = range1.offset(1, 0);
var offset2 = range1.offset(2, 0);
//substring cannot run on numbers, so...
cellValue = range1.getValue();
if (typeof cellValue === 'number') {continue;};
dash = cellValue.substring(0, 1);
//if -
if (dash === "-") {
offset1.setFontColor('red');
offset2.setBackground('green');
};
};
You can use all the various spreadsheet methods to get and set colors, font sizes, font weights, etc. to and from distinct arrays but you can not mix these "attributes" in one single item. See the doc here.
Or even handier, in your script editor write a script that defines a range and play with the auto complete to see everything you can do with it...
(control+space keys)
edit following your code update.
You should create a second array that holds all the background colors of your range and fill it according to your needs.
In the code below I build the array in parrallels with your output array, not very elegantly but rather systematically to show how it works.
Note that null value means "no background color" while #0F0 is the hexadecimal code for green but you can also use the 'green' string if you prefer...
...
var output = [];
var backGrounds=[]
//loop through all cells in column A
for (row = 0; row < lastRow; row++) {
var cellValue = data[row][0];
var dash = false;
if (typeof cellValue === 'string') {
dash = cellValue.substring(0, 1);
//if a number copy to our output array
} else {
output.push([cellValue]);
backGrounds.push([null]);
}
//if -dash
if (dash === "-") {
//build first + last name
var name = (data[(row+1)][0]+" "+data[(row+2)][0]).trim();
//add row for the -state (e.g. -MI)
output.push([cellValue]);
backGrounds.push([null]);
output.push([name]);
backGrounds.push([null]);
output.push(["Order complete"]);
backGrounds.push(['#0F0']);
//add a blank row
output.push([""]);
backGrounds.push([null]);
//jump an extra row to speed things up
row++;
}
}
s.getRange(1, 1, output.length).setBackgrounds(backGrounds);
...
REMARK: The OP did a huge change from revision 1 to revision 3. Following is the content taken from the source of the revision 1.
Is it possible to push text to a spreadsheet with formatting such
as .setFontColor, .setBackgroundColor or .setBorder? I've been
monkeying around with code but never get an error message. It just
doesn't do anything. I'm working with something like this:
if (cell === "This should be red") {
var redCell = (data[(row)][0]).setFontColor('red');
array.push([redCell]);
}
Following is my answer to the revision 1.
To copy the value and format from one cell or range to another use copyTo(destination).
From the above link
// The code below will copy the first 5 columns over to the 6th column.
var sheet = SpreadsheetApp.getActiveSheet();
var rangeToCopy = sheet.getRange(1, 1, sheet.getMaxRows(), 5);
rangeToCopy.copyTo(sheet.getRange(1, 6));
}
Related
I have a sheet to monitor inventory. I have a script in the sheet to copy values of rows with data and paste to the first available row on another sheet and then clear the content. This leaves holes in my data on the original sheet. I want to consolidate all my data up to the first available cells in a column so there would never be empty rows between rows with data. Unfortunately, I can't do the same thing I do with the other sheet, as I have certain columns in my row which have formulas that need to remain (Sum formulas to figure weight, etc). If I grab the entire row, it messes up my formulas or the formulas mess up the script (row is not available because it contains a value). So basically what I have is this:
Sheet1 name = 'CURRENT MONTH'
Sheet2 name = 'SHIPPED INVENTORY'
Total Range with data on Sheet1 = A11:W61
Ranges with data that needs to shift up = A11:O61, R11:S61, V11:W61
Ranges with formulas that cannot shift = P11:Q61, T11:U61
I've searched what I could but either I cannot word my dilemma correctly or the answers are beyond my skill level and I can't make them work for me. Any assistance is greatly appreciated!
Without seeing how you are moving your information from one sheet to another, this code copies the entire row to the first row of the inventory sheet:
function myFunction ()
{
...
var ss = SpreadsheetApp.getActiveSpreadsheet ();
var month_sheet = ss.getSheetByName ("CURRENT MONTH");
var shipped_sheet = ss.getSheetByName ("SHIPPED INVENTORY");
var month_values = month_sheet.getDataRange ().getValues ();
for (var i = 11; i < month_values.length && i <= 61; i++)
{
if (test_value) // This is a row you want to move to the other sheet
{
// Create a row in the SHIPPED INVENTORY sheet,
// and copy the full row into it
shipped_sheet.insertRowAfter (1); // Assuming a header row
var shipped_row_1= shipped_sheet.getRange (2, 1); // Get second row in file
var month_range = month_sheet.getRange ((i + 1), 1, 1, month_sheet.getMaxColumns ());
month_range.copyTo (shipped_row_1);
// Now move everything else up
moveRangeUp (month_sheet, "A", i, "O61");
moveRangeUp (month_sheet, "R", i, "S61");
moveRangeUp (month_sheet, "V", i, "W61");
i--; // Since everything moved up, check this row's new information
}
}
...
}
function moveRangeUp (sheet, first_col, row, last_col_row)
{
var from_a1Notation = first_col + (i + 1) + ":" + last_col_row;
var to_a1Notation = first_col + (i);
var copy_range = sheet.getRange (from_a1Notation);
var to_range = sheet.getRange (to_a1Notation);
copy_range.copyTo (to_range);
// After shift up, delete last row of data, since it is also moved up
// Always assuming that the last row is row 61
var delete_a1Notation (first_col + "61:" + last_col_row);
var delete_range = sheet.getRange (delete_a1Notation);
var delete_range.clear ();
}
I want to reduce the calls to sheet.getRange in the following function, because the execution times out.
I've tried re-arranging the loops and parsing the data as a double array, however the size of my spreadsheet changes every day and I need to be able to reference the columns by name only.
function runDuplicateRemover() {
var sheet= SpreadsheetApp.getActive().getSheetByName('Sheet 1');
var rangeData = sheet.getDataRange();
var lastRow = rangeData.getLastRow();
var Cdata = sheet.getDataRange().getValues();
// here I am accessing the column which is used to find duplicates
var colCRM = Cdata[0].indexOf("CRM ID")+1;
var arrayOfDuplicates = [];
for(i=1; i<lastRow; i++){
var cellToCompare = sheet.getRange(i+1,colCRM);
// I am just changing all the colors to see the execution
cellToCompare.setBackground("#88b4fc");
var crmToCompare =cellToCompare.getValue();
//checks to see that this value is not already contained in the rows to delete
if (!cellToCompare.isBlank() && (arrayOfDuplicates.indexOf(i)+1)==0 ){
arrayOfDuplicates.push(i);
cellToCompare.setBackground("#f9d9f9");
for (j = i+1; j<lastRow; j++) {
var cellCurrent = sheet.getRange(j+1,colCRM);
cellCurrent.setBackground("#f2fc88");
var crmCurrent = cellCurrent.getValue();
if (crmToCompare == crmCurrent) {
arrayOfDuplicates.push(j);
cellCurrent.setBackground("#fc92f1");
}
}
//pops last value since that's the only one I want to keep
sheet.getRange(arrayOfDuplicates.pop()+1,colCRM).setBackground("#dbf7d4");
}
}
for (t = arrayOfDuplicates.length-1; t>=0; t--) {
sheet.deleteRow(arrayOfDuplicates[t]+1);
}
}
I'd like to reduce the calls to the sheet.getRange, however I don't know how to delete the rows and then return the data back to the sheet without messing all the column order up.
I am trying to compare the data from 2 google sheets. Each sheet has a column that is the identifier (sheet1:H and sheet2:C), if these match then I want to change sheet1:I to the value in sheet2:E. I'm running this code, but get no errors. It's not working though.
I tried to see similar posts this issue but they all seem to be lacking the compare a different column method I am using.
function changestatus() {
// gets spreadsheet A and the range of data
ssA = SpreadsheetApp.openById('IDHERE');
sheetA = ssA.getSheetByName('Sheet1');
dataA = sheetA.getRange('H2:H').getValues();
dataD = sheetA.getRange('I2:I').getValues();
// gets spreadsheet B and the range of data
ssB = SpreadsheetApp.openById('IDHERE');
sheetB = ssB.getSheetByName('responses');
dataB = sheetB.getRange('C2:C').getValues();
dataC = sheetB.getRange('E2:E').getValues();
for (var i = 0; i > sheetA.getLastRow(); i++) {
if (dataA[1][i] == dataB[1][i] && dataC[1][i] != dataD[1][i]){
var value = sheetA.getRange(i+1, 2).getValue(dataD);
sheetB.getRange(i+1, 2).setValue(value);
} // end if
} // end i
Starting results of sheets files would be something like:
Sheet 1
H:(ID) 1 I:(grade) pass
Sheet 2
C:(ID) 1 E:(grade) fail
After Function:
Sheet 1
H:(ID) 1 I:(grade) fail
#tehhowch is quite right; you need to review JavaScript comparison operators, for loop syntax, the format of object returned by Range#getValues, and how to access JavaScript array indices. Each of these contributes to your code problems, but it's reasonable that that we help you along the road a little more.
Loop syntax
This is an easy one. Instead of "i > sheetA.getLastRow()", it should read i < sheetA.getLastRow(). i starts with a value of zero, and its value increases by one at the end of each loop; so you want the loop to process all the values of i that are less than the value of the last row.
Array values
getValues returns a two-dimensional array but the IF statement fails because the array values are back to front.
For example, instead of "dataA[1][i]", it should be dataA[i][0]. There are two changes here:
1 - "i" moves to the first half of the array value (the 'row' value); and
2 - the second half of the array value is [0] (not "[1]"). This is because each variable is only one column wide. For example, dataA only returns the value of column H; same is true for dataB, dataC and dataD - they all return the value of just one column.
Troubleshooting
How could you tell whether the IF statement was a problem? It "looks" OK. One way is to display (or log) the values being returned.
I use Logger.log() (there are other options) to display information in the script editor under "View, Logs". Each time the script is run, the "Logger" statements are updated and you can check their value.
For example, you could insert this code at line 13 (before the loop) to check some values of the data variables.
Logger.log("dataA[1][0] = "+dataA[1][0]);
That line will show: "dataA[1][0] = 2". That's a valid result but you might notice that it is reporting ID=2 but, say, you were expecting a result of ID=1.
So change the line to:
Logger.log("dataA[1][1] = "+dataA[1][1]);
This line shows "dataA[1][1] = undefined". OK, something definitely wrong.
So, let's try:
Logger.log("dataA[0][0] = "+dataA[0][0]);
This line shows "dataA[0][0] = 1". Now that's more like it.
You can make Logger long or short; for example, you might want to evaluate the results of of the variables in one line. So the Logger might look like this:
Logger.log("dataA[0][0] = "+dataA[0][0]+", dataB[0][0] = "+dataB[0][0]+", dataC[0][0] = "+dataC[0][0]+", dataD[0][0] = "+dataD[0][0]);
And it would return:
"dataA[0][0] = 1, dataB[0][0] = 1, dataC[0][0] = Fail, dataD[0][0] = Pass".
This might confirm that you are on the right track, or that you need to debug further
The Failing IF statement
Original line = "(dataA[1][i] == dataB[1][i] && dataC[1][i] != dataD[1][i])"
Corrected line = (dataA[i][0] == dataB[i][0] && dataC[i][0] != dataD[i][0])
Updating the results on Sheet 1
The code here is:
var value = sheetA.getRange(i+1, 2).getValue(dataD);
sheetB.getRange(i+1, 2).setValue(value);
This is confusing and complicates a couple of things.
1 - the value just needs to be "the value in sheet2:E - this was in the IF statement: dataC[i][0]. So value = dataC[i][0]
2 - The goal is "change sheet1:I to the value in sheet2:E". You've already got the value, so focus now on sheet1:I.
Some times it is more simple to define the range and then, on a second line, update the value for that range.
the target sheet is sheetA;
the target row is: i+1 (that was correct);
the target column is: I (or column 9).
So, var range = sheetA.getRange(i+2, 9);
You could check this with "Logger":
Logger.log("range = "+range.getA1Notation()); might return "range = I2".
Then update the value:
range.setValue(value);
Meaningful variable names
It helps (a LOT) to use meaningful variable names. For example, the original code uses:
"dataA" = Sheet1, Column H (contains ID); so maybe this could be "data1_H" or even "targetID.
"dataD" = Sheet1, Column I (contains grade); so maybe this could be "data1_I" or targetGrade.
"dataB" = Sheet2, Column C (contains ID), so maybe this could be "data2_C" or sourceID.
"dataC" = Sheet2, Column E (contains grade); so maybe this could be "data2_E" or sourceGrade.
Summary of changes
function so_changestatus() {
// gets spreadsheet A and the range of data
ssA = SpreadsheetApp.openById('IDHERE');
sheetA = ssA.getSheetByName('Sheet1');
dataA = sheetA.getRange('H2:H').getValues();
dataD = sheetA.getRange('I2:I').getValues();
// gets spreadsheet B and the range of data
ssB = SpreadsheetApp.openById('IDHERE');
sheetB = ssB.getSheetByName('responses');
dataB = sheetB.getRange('C2:C').getValues();
dataC = sheetB.getRange('E2:E').getValues();
for (var i = 0; i < sheetA.getLastRow(); i++) {
if (dataA[i][0] == dataB[i][0] && dataC[i][0] != dataD[i][0]){
var value = dataC[i][0];
var range = sheetA.getRange(i+2, 9);
range.setValue(value);
} // end if
}
}
UPDATE - 1 April 2019
ID on SheetA vs SheetB does NOT match row-by-row
The original code was written on the basis that the ID matched on a row-by-row basis. This is not the case. So a variation in the code is needed to test whether the ID on SheetA exists on SheetB, and then test the respective status.
The evaluation of the sheetA ID on sheetB is done with [indexof] Docs reference.
In this code, I also took the opportunity to make the variable names of the data ranges more meaningful.
Note also: the loop continues while i is less than the lastrow minus one "i < (lastrow-1);". This is necessary because the first row are headers and the data range starts on row 2, so the number of data rows will be the "lastrow minus one" (to a allow for the header row).
function ejb2so_changestatus() {
// gets spreadsheet A and the range of data
// ssA = SpreadsheetApp.openById('IDHERE');
ssA = SpreadsheetApp.getActive();
sheetA = ssA.getSheetByName('Sheet1');
dataA_ID = sheetA.getRange('H2:H').getValues();
data_Status = sheetA.getRange('I2:I').getValues();
//Logger.log("DEBUG: H3 = "+dataA_ID[4][0]+", I3 = "+data_Status[4][0]);//DEBUG
// gets spreadsheet B and the range of data
//ssB = SpreadsheetApp.openById('IDHERE');
ssB = SpreadsheetApp.getActive();
sheetB = ssB.getSheetByName('Responses');
dataB_ID = sheetB.getRange('C2:C').getValues();
dataB_Status = sheetB.getRange('E2:E').getValues();
// Logger.log("DEBUG: C3 = "+dataB_ID[0][0]+", E3 = "+dataB_Status[0][0]);//DEBUG
var lastrow = sheetA.getLastRow()
// Logger.log("DEBUG: sheetA last row = "+lastrow);//DEBUG
// Flatten the array
var dataB_IDFlat = dataB_ID.map(function(row) {
return row[0];
});
//Loop through values on sheetA; check if they exist on sheetB
for (var i = 0; i < (lastrow - 1); i++) {
var A_ID = dataA_ID[i][0];
// Logger.log("DEBUG: id = "+A_ID);//DEBUG
// assign variable to return value index
var result = dataB_IDFlat.indexOf(A_ID);
if (result != -1) {
// it's there
// Logger.log("DEBUG: i: "+i+", ID: "+A_ID+", it's there"+", result#: "+result);//DEBUG
// Logger.log("DEBUG: Sheet1 status: "+data_Status[i][0]+" Vs Sheet2 status = "+dataB_Status[result][0]);//DEBUG
// compare status from sheetsA to sheetB
if (data_Status[i][0] != dataB_Status[result][0]) {
// Logger.log("DEBUG: status change to: "+dataB_Status[result][0]);//DEBUG
var range = sheetA.getRange(i + 2, 9);
//Logger.log("DEBUG: value = "+value);//DEBUG
//Logger.log("DEBUG: range = "+range.getA1Notation());//DEBUG
range.setValue(dataB_Status[result][0]);
}
} else {
// it's not there
// Logger.log("DEBUG: i: "+i+", ID: "+A_ID+", it's not there");//DEBUG
}
}
}
// Credit: Flatten array: https://stackoverflow.com/a/49354635/1330560
I've been using the Google-provided script to generate and email CSVs from Google Sheets. I customised it so that it doesn't ask for a range or a file name. This way it just automatically emails me, periodically, with the contents of my range.
The problem is that the CSV contains empty rows, at the end, that I'd like the script to automatically filter out (which I can't achieve, because I just don't have the knowledge). The reason for this, in turn, is that the range contains empty rows - but there's a good reason for that, which is that the rows in the range sometimes expand, sometimes contract, depending on the underlying data. (The range in fact relates to a pivot table).
As a bonus prize, I'd also really like it to skip rows, if there is a single zero in either of the two columns in the rows. (I ought to be able to filter this out in the pivot table; I can, but then the filters don't work properly if new values appear).
This is an example of how my emailed CSVs are looking at the moment:
0,0
,0
0.65,0
0.75,16900
0.78,2000
0.79,500
0.8,110800
0.83,1200
0.85,20000
0.87,4500
0.9,3500
1,5000
1.1,4000
1.2,41500
,
,
,
,
,
,
,
,
,
,
,
,
,
,
This is an example of how I would like to receive that CSV:
0.75,16900
0.78,2000
0.79,500
0.8,110800
0.83,1200
0.85,20000
0.87,4500
0.9,3500
1,5000
1.1,4000
1.2,41500
Any help with this would be HUGELY appreciated. Thanks.
Here's the script I'm using currently:
var settings = {
"recipients": "myemailaddress",
"emailSubject": "CSV file",
"emailMessage": "Your CSV file is attached",
"fileExtension": ".csv",
"carriageReturn": "\r\n"
};
function onOpen() {
var subMenus = [];
subMenus.push({name: "Email Named Range as CSV", functionName: "run"});
SpreadsheetApp.getActiveSpreadsheet().addMenu("CSV", subMenus);
}
function run() {
/var namedRange = Browser.inputBox("Enter named range to convert to CSV (e.g. sampleDataRange):");/
var namedRange = "FORCSVEXPORT";
var fileName = "EPCSELLOFFERS.CSV";
if (namedRange.length !== 0 && fileName.length !== 0) {
settings.dataRangeName = namedRange;
settings.csvFileName = fileName + settings.fileExtension;
var csvFile = convertNamedRangeToCsvFile_(settings.dataRangeName, settings.csvFileName);
emailCSV_(csvFile);
}
else {
Browser.msgBox("Error: Please enter a named range and a CSV file name.");
}
}
function emailCSV_(csvFile) {
MailApp.sendEmail(settings.recipients, settings.emailSubject, settings.emailMessage, {attachments: csvFile});
}
function convertNamedRangeToCsvFile_(rngName, csvFileName) {
var ws = SpreadsheetApp.getActiveSpreadsheet().getRangeByName(rngName);
try {
var data = ws.getValues();
var csvFile = undefined;
if (data.length > 1) {
var csv = "";
for (var row = 0; row < data.length; row += 1) {
for (var col = 0; col < data[row].length; col += 1) {
if (data[row][col].toString().indexOf(",") != -1) {
data[row][col] = "\"" + data[row][col] + "\"";
}
}
// Join each rows columns
// Add carriage return to end of each row
csv += data[row].join(",") + settings.carriageReturn;
}
csvFile = [{fileName: csvFileName, content: csv}];
}
return csvFile;
}
catch(err) {
Logger.log(err);
Browser.msgBox(err);
}
}
Rather than hack the original convertNamedRangeToCsvFile_(), I propose adding an additional step to your run(), that will call a new function to remove the unwanted rows from the csv file. Here it is:
/**
* Remove unwanted lines from given csvFile
*/
function minimizeCsvFile( csvFile ) {
// take apart the csv file contents, into an array of rows
var rows = csvFile[0].content.replace(/\r\n/g, "\n").split("\n");
var newRows = [];
for (var i = 0; i < rows.length; i++ ) {
if (rows[i] == "") continue; // skip blanks
if (rows[i] == ",") continue; // skip null values
// skip rows with either numeric value == 0
var vals = rows[i].split(",");
if (parseFloat(vals[0]) == 0.0 || parseFloat(vals[1]) == 0.0) continue;
// If we got here, we have a keeper - add it to newRows
newRows.push(rows[i]);
}
debugger; // pause to observe in debugger
var csv = newRows.join(settings.carriageReturn);
// Return a single element array with an object, exactly like
// the one from convertNamedRangeToCsvFile_.
return [{fileName: csvFile[0].fileName, content: csv}];
}
To make use of it, change the emailCSV_() line in run() to:
var minimizedCsvFile = minimizeCsvFile(csvFile);
emailCSV_(minimizedCsvFile);
And as for this...
As a bonus prize... Any help with this would be HUGELY appreciated. Thanks.
All we ever want here is for new members of StackOverflow to acknowledge when they receive help! Have a look at this answer for tips on how to accept answers. (You can build rep by asking, answering and accepting answers!)
But I've always wanted a Ferrari...
I am trying to write a script in Google Apps Script that takes cell information from one sheet and copies it to another sheet, both for just grabbing certain columns to display on the second sheet and also a condition based on the values inside cells in a certain column. Here is what I have so far:
function onMyEdit() {
var myMaster = SpreadsheetApp.openById("xxxxx");
var masterSheet = myMaster.setActiveSheet(myMaster.getSheets()[0]);
var myNames = SpreadsheetApp.openById("xxxxx");
var namesSheet = myNames.setActiveSheet(myNames.getSheets()[0]);
var row1 = masterSheet.getRange(1, 1, masterSheet.getLastRow(), 1);
var rowV = row1.getValues();
var firstArray = masterSheet.getDataRange().getValues();
var dataList = [];
for (var i = 1; i < rowV.length; i++) {
dataList.push(firstArray[i][0]);
dataList.push(firstArray[i][1]);
dataList.push(firstArray[i][2]);
dataList.push(firstArray[i][3]);
}
for (var j = 0; j < rowV.length - 1; j++) {
namesSheet.getRange(2, j + 1, 1, 1).setValue(dataList[j]);
}
}
So as of now it only works on one row, starting from the second row (to allow for column headers). And I suppose when I want to grab rows conditionally based on cell data, I will use an 'if' statement for the condition inside the 'for' loop, but I want the data to copy to the next available row in both sheets. I suppose I'd use something like:
' getLastRow + 1 '
or something like that. I need this code to be as efficient as possible because of the amount of data and its purpose. I am pretty new to programming so please explain in detail, and thanks again.
I'm not sure I understood exactly what you wanted to do but -from what I understood- this code snippet should give you a better way to start with...
(I added a few comments to explain in the code itself)
function onMyEdit() {
var myMaster = SpreadsheetApp.openById("MasterSheet ID");
var masterSheet = myMaster.getSheets()[0]; // get 1rst sheet
var myNames = SpreadsheetApp.openById("NamesSheet ID");
var namesSheet = myNames.getSheets()[0]; // get 1rst sheet
var firstArray = masterSheet.getDataRange().getValues();
var dataList = [];
for ( r = 1; r < firstArray.length; r++) { // iterate the first col of masterSheet
if(firstArray[r][0]=='some condition'){ // if value in the first column == 'some condition get the second column cell in the new array (here you could change what you want to get)
dataList.push([firstArray[r][1]])
}
}
Logger.log(dataList)
if(dataList.length>0){
namesSheet.getRange(1,namesSheet.getLastColumn()+1,dataList.length,1).setValues(dataList);//copy data in a column after last col
}
}