Basically I have an array of information that I can currently append into google sheets, the thing is that a lot of the information is not necessary for my need so I wanted to find a way to just append the columns I need.
The picture above shows how everything looks,
basically the idea is to make it looks like in the following picture.
so basically I only need to append columns 4,5,7
currently why I do is this!
if (tozip.getContentType() == "application/zip"){ //for ZIP files
var unZip = Utilities.unzip(tozip); //assigns the unzipped file to a new variable
var table = Utilities.parseCsv(unZip[0].getDataAsString());// assigns the data to variable
for (var i = 0; i < table.length; i++) {//loops trought the array an appends the data as it goes.
sheet.appendRow(table[i]);
}
the data comes from a csv file and looks like this.
[[isApplication, applicationDate, isQualified, Funded_Date, isFunded, requested_loan_amount, amountFunded], [1, 2020-02-03, 1, 2020-02-03, 1, , 1300.0000], [1, 2019-12-29, 1, 2019-12-30, 1, 3000.0000, 2000.0000], [1, 2020-01-27, 1, 2020-01-28, 1, , 800.0000], [1, 2020-01-08, 1, 2020-01-10, 1, 2500.0000, 2500.0000], [1, 2020-02-04, 1, 2020-02-10, 1, , 1400.0000], [1, 2020-01-21, 1, 2020-01-21, 1, 5000.0000, 2000.0000], [1, 2020-02-06, 1, 2020-02-06, 1, 1100.0000, 1400.0000], [1, 2020-02-01, 1, 2020-02-04, 1, 1500.0000, 601.0000], [1, 2020-02-11, 1, 2020-02-11, 1, 500.0000, 800.0000]]
so yeah a lot of messy csv data.
I tried adding this to the code and a few variations of it so It can select the inside data
for (var i = 0; i < table.length; i++) {//loops trought the array an appends the data as it goes.
var columns = [];
columns.push(3);
columns.push(4);
columns.push(6);
sheet.appendRow(table[i][columns]);
}
but it does not work I'm super new to this type of stuff, so I'm pretty sure that's not the correct way to try and select the information I want from the array.
let me know if I need to elaborate more on this, I'm not super good at explaining this stuff.
Thank you in advance for the answers I really appreciate the help on this.
You want to retrieve the columns "D", "E" and "G" from the data retrieved by parsing the CSV data.
In your script, table of var table = Utilities.parseCsv(unZip[0].getDataAsString()); is the 2 dimensional data shown in your question.
You want to put the retrieved values to the Spreadsheet.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Modification points:
table of var table = Utilities.parseCsv(unZip[0].getDataAsString()); is 2 dimensional array.
When for (var i = 0; i < table.length; i++) {} is used, each row can be retrieved by table[i]. And the values from the columns "D", "E" and "G" can be retrieved by table[i][3], table[i][4], table[i][6].
In this modification, var values = [] is prepared, and each row is put with values.push([table[i][3], table[i][4], table[i][6]]).
When the method of appendRow() is used in the for loop, the process cost becomes high. So in this case, an array is created in the for loop. And the array is put to the Spreadsheet using setValues(). By this, the cost can be reduced.
When above points are reflected to your script, it becomes as follows.
Modified script:
var table = Utilities.parseCsv(unZip[0].getDataAsString());
// I modified below script.
var values = [];
for (var i = 0; i < table.length; i++) {
values.push([table[i][3], table[i][4], table[i][6]]);
}
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
sheet.getRange(sheet.getLastRow() + 1, 1, values.length, values[0].length).setValues(values);
Above script, the values are put to "Sheet1". If you want to change this, please modify getSheetByName("Sheet1").
In this case, table is var table = Utilities.parseCsv(unZip[0].getDataAsString()).
Note:
When var table = Utilities.parseCsv(unZip[0].getDataAsString()) doesn't return the array of CSV data, above modified script cannot be used. Please be careful this.
References:
parseCsv(csv)
getRange(row, column, numRows, numColumns)
setValues(values)
If I misunderstood your question and this was not the direction you want, I apologize.
Related
I'm trying to leave a blank column in between data of an appended row, so that I can add a VLOOKUP function, functionally I don't need to do this (I could just add the VLOOKUP to the end of the row), but aesthetically it would be better if I could. Is there a way to just skip a column when appending data into a row?
Explanation:
You can use two separate setValues statements to achieve your goal and paste the data right after the last row with content with getLastRow().
I have fully described each block of lines in the following script so I think it is straightforward to work with it.
I tried to create a generic code where you can select:
the column you want to separate the data: sep_col
the starting column you want to paste the data: start_col
the number of columns you want to have between the two different datasets: space_col
Code snippet:
function myFunction() {
// get spreadsheet details
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet1'); // change that to the name of your sheet
// provide some data
const sep_col = 3; // column you want to separate the data
const data = ["d1","d2","d3","d5","d6"];
const data1 = data.slice(0,sep_col);
const data2 = data.slice(sep_col,data.length);
// get current last row of document
const Lrow = sh.getLastRow();
// paste the data to separate ranges
const start_col = 1;
const space_col = 1;
sh.getRange(Lrow+1,start_col, 1, data1.length).setValues([data1]);
sh.getRange(Lrow+1,start_col+data1.length + space_col, 1, data2.length).setValues([data2]);
}
JavaScript References:
Array.prototype.slice()
Sheet used for the code snippet:
I do SEO, and therefore I have a lot of keywords flowing around in different spreadsheets. I'd like a way to filter these into seperate sheets based on specific filters, but I can't for the life of me, figure out how to do this in Google Apps Script.
Criteria I set myself for this to work out:
A list of strings and their corresponding volumes are entered in column 1+2.
A list of filter-words are written in column 3.
The script has to create a new sheet for each of the filter words and move the strings + volumes into these different sheets if the string contains a filter word.
Example:
Filter words: Apple, Banana, Pineapple
String: "The Apple Was Big", Volume: "100"
The script would move the string and volume into the sheet called "Apple" on row 1
(Beware, I'm in no means experienced in coding)
I believe you can use the following structure:
for(let i = 0; i <= column3RowAmount; i++){ //Run as long as there are more filter words
create(column3Row[i]); //create a new sheet with the name of the filter word
for(let j = 0; j <= column1RowAmount; j++){ //Run as long as there are more keywords
if(column1Row[j].indexOf(column3Row[i]) >= 0){ //If the Row in column 1 contains the filter word
column1Row[j].moveToSheet(column3Row[i]); // Make sure not to move Column 3, but only 1+2
}
}
}
Example sheet: https://docs.google.com/spreadsheets/d/15YIMyGmmfZdy094gwuJNxFmTd8h7NOLnA8KevZrGtdU/edit?usp=sharing
Explanation:
Your goal is to create a sheet for every filter-word in column C. Then copy the data in columns A, B but only the rows that include the filter-word to the corresponding sheet.
For starters, you need to get the filter-word list. You can get the full range of column C and filter out the empty cells:
const sh_names = sh.getRange('C1:C').getValues().flat().filter(r=>r!='');
Similarly, you need to get the data in columns A and B:
const data = sh.getRange('A1:B'+sh.getLastRow()).getValues();
The next step is to iterate over sh_names and for every element / filter-word, check if a sheet with that name exists. If it does not exist, then create a sheet with that name, if it exists then skip the creation part:
if(!ss.getSheetByName(s)){
ss.insertSheet().setName(s);}
The next step is to filter data on the rows that include the filter-word:
let f_data = data.filter(r=>r[0].includes(s));
Finally, check if the length of the data is bigger than 0, otherwise there is not data to use and set the values of data to the corresponding sheet:
sheet.getRange(sheet.getLastRow()+1,1,f_data.length,f_data[0].length).setValues(f_data)
Solution
function myFunction() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Ark1');
const filter_sh = ss.getSheetByName('Filter');
const data = sh.getRange('A1:B'+sh.getLastRow()).getValues();
const sh_names = filter_sh.getRange('A1:A'+filter_sh.getLastRow()).getValues().flat();
sh_names.forEach(s=>{
if(!ss.getSheetByName(s)){
ss.insertSheet().setName(s);}
let sheet = ss.getSheetByName(s);
let f_data = data.filter(r=>r[0].includes(s));
if(f_data.length>0){
sheet.getRange(sheet.getLastRow()+1,1,f_data.length,f_data[0].length).setValues(f_data);}
});
}
This function will place all of your results into column 4 next to the appropriate word rather than creating a page for each word. So it runs much faster.
function stringswords() {
const ss=SpreadsheetApp.getActive();
const sh=ss.getSheetByName('Sheet1');
const sr=2;
const rgd=sh.getRange(sr,1,sh.getLastRow()-sr+1,2);
const data=rgd.getDisplayValues();
const rgw=sh.getRange(sr,3,sh.getLastRow()-sr+1,1);
const words=rgw.getDisplayValues().flat();
const wiObj={};
words.forEach(function(w,i){wiObj[w]=i});
const rgr=sh.getRange(sr,4,sh.getLastRow()-sr+1,1);
rgr.clearContent();
var results=rgr.getValues();
words.forEach(function(w,i,A){
data.forEach(function(r,j,D) {
if(data[j][0] && data[j][0].indexOf(w)!=-1) {
results[wiObj[w]][0]+=Utilities.formatString('String:%s Vol:%s\n',data[j][0],data[j][1]);
}
});
});
rgr.setValues(results);
}
Image of Data and output:
I want to compare two sheets (based on header values in row 1) and delete any column with a unique value (without a match). For example, Assuming Sheet1, Row 1 data and Sheet 2, Row 1 are uniform, if a user adds/deletes a column within any sheet, I want to always match the number of columns in both sheets with their values
Screenshots of sheets headings.
IF both sheets looks like this
And a user adds a new Column N
Or delete column N
How can I ensure that both sheet matches by deleting the odd/distinct column in Sheet 1?
I have tried modifying this code below but I can't just get the unique one out. This code only look for headers with a defined value.
function deleteAloneColumns(){
var sheet = SpreadsheetApp.getActiveSheet();
var lastColumnPos = sheet.getLastColumn();
var headers = sheet.getRange( 1 ,1, 1, lastColumnPos ).getValues()[0];
for( var i = lastColumnPos ; i < 1; i--){
if( headers[i] === "alone" ) sheet.deleteColumn(i);
}
SpreadsheetApp.getUi().alert( 'Job done!' );
}
Any help to compare and delete the column with the unique value will be appreciated.
Problem
Balancing sheets based on header row values mismatch.
Solution
If I understood you correctly, you have a source sheet against which validation is run and two primary use cases: user adds a new column named differently than any other column (if you want to check that the column strictly matches the one in sheet1, it is easy to modify) in source sheet or deletes one that should be there.
const balanceSheets = (sourceShName = 'Sheet1',targetShName = 'Sheet2') => {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const s1 = ss.getSheetByName(sourceShName);
const s2 = ss.getSheetByName(targetShName);
const s2lcol = s2.getLastColumn();
//keep all vals from source to reduce I/O
const s1DataVals = s1.getDataRange().getValues();
const s2Vals = s2.getRange(1, 1, 1, s2lcol).getValues();
const h1Vals = s1DataVals[0];
const h2Vals = s2Vals[0];
//assume s1 is source (validation) sheet
//assume s2 is target sheet that a user can edit
//case 1: target has value not present in source -> delete column in target
let colIdx = 0;
h2Vals.forEach(value => {
const isOK = h1Vals.some(val => val===value);
isOK ? colIdx++ : s2.deleteColumn(colIdx+1);
});
//case 2: target does not have values present in source -> append column from source
h1Vals.forEach((value,index) => {
const isOK = h2Vals.some(val => val===value);
!isOK && s2.insertColumnAfter(index);
const valuesToInsert = s1DataVals.map(row => [row[index]]);
const numRowsToInsert = valuesToInsert.length;
s2.getRange(1,index+1, numRowsToInsert,1).setValues(valuesToInsert);
});
};
Showcase
Here is a small demo of how it works as a macros:
Notes
Solving your problem with two forEach is suboptimal, but I kept number of I/O low (it can be lowered further by, for example, moving deleteColum out of the loop while only keeping track of column indices).
The script uses ES6 capabilities provided by V8, so please, be careful (although I would recommend migrating as soon as possible - even if you encounter bugs / inconsistencies , it is worth more than it costs.
UPD made script more flexible by moving sheet names to parameter list.
UPD2 after discussing the issue with deleteColumn() behaviour, the answer is updated to keep column pointer in bounds (for those curious about it - forEach kept incrementing the index, while deleteColumn reduced bounds for any given index).
Reference
insertColumnAfter() method reference
There are 3 duplicate articles from the same domain in Sheet1: https://docs.google.com/spreadsheets/d/1pExqHJQubnSPDKczkF9HMA2QN1cxTYmzyewQdugDRYs/edit#gid=0
Goal: I'd like to remove articles that have the same title AND domain.
Sheet DesiredResult has the desired result.
I'd like to modify this filter script to compare article title(column a) & domain(column C), if they are the same, then remove:
function removeDuplicates() {
const sheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
const data = sheet.getDataRange().getValues();
var temp = {}; // Added
var newData = data.filter(function(e) { // Added
if (!temp[e[1]]) {
temp[e[1]] = e[1];
return true;
}
return false;
});
sheet.clearContents();
sheet.getRange(1, 1, newData.length, newData[0].length).setValues(newData);
}
Right now it just looks at the link if they're the same. It's not using an if statement so I'm not sure how to add a comparison for 2 columns. Any help is appreciated, thanks!
Update: I've tried looking at !temp[e[1]] to see if there are values to compare in an if statement but it shows as undefined so I'm stuck where to add the second column comparison in this section.
Reference: Previous question, asked to compare 1 column - Google Sheet Scripts: How to compare only one column to remove duplicates
You want to remove the duplicated rows by comparing the column "A" and "C".
In your shared spreadsheet, you want to modify from Sheet1 to DesiredResult.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this modification? In this modification, the method of removeDuplicates() is used. This was added at July 26, 2019. So your question had been posted at July 15, 2019, unfortunately, at that time, this method had not been added yet. Please think of this as just one of several answers.
Modified script:
const sheet = SpreadsheetApp.getActive().getSheetByName('Combined');
sheet.getDataRange().removeDuplicates([1, 3]);
Note:
When you test above modified script to the shared Spreadsheet, please modify the sheet name from Combined to Sheet1.
Reference:
removeDuplicates(columnsToCompare)
If I misunderstood your question and this was not the result you want, I apologize.
Added:
If you want to modify your script, how about the following modification? Also please think of this just one of several answers.
From:
if (!temp[e[1]]) {
temp[e[1]] = e[1];
To:
if (!temp[e[0] + e[2]]) {
temp[e[0] + e[2]] = e[1];
function removeDuplicates() {
var sheet=SpreadsheetApp.getActive().getSheetByName('Sheet1');
var data=sheet.getDataRange().getValues();
var newData = data.filter(function(r) {
return !(r[0]==r[2])//comparing column A with Column C
});
sheet.clearContents();
sheet.getRange(1, 1, newData.length, newData[0].length).setValues(newData);
}
Test it on this Data:
1,a,a
2,b,a
3,c,a
4,a,a
5,b,a
6,c,6
7,a,7
8,b,8
9,c,9
Array.filter()
I am writing a script for google sheet validation on localization tests. I've gotten stuck on some of the logic. The purpose of the script is to 1) Iterate through all tabs. 2) Find the column on row 2 that has the text "Pass/Fail". Lastly, 3) Iterate down that column and return the rows that say Fail.
The correct script to look at is called combined(). Step 1 is close to being correct, I think. Step 2 has been hard coded for the moment and is not dynamic searching the row for the text. Step 3 is done.
Any help would be great :)!!! Thanks in advance.
https://docs.google.com/spreadsheets/d/1mJfDtAi0hHqhqNB2367OPyNFgSPa_tW9l1akByaTSEk/edit?usp=sharing
/*This function is to cycle through all spreadsheets.
On each spreadsheet, it will search the second row for the column that says "Pass/Fail".
Lastly, it will take that column and look for all the fails and return that row*/
function combined() {
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var r =[];
for (var i=0 ; i<sheets.length ; i++){//iterate through all the sheets
var sh = SpreadsheetApp.getActiveSheet();
var data = sh.getDataRange().getValues(); // read all data in the sheet
//r.push("test1"); //Testing to make sure all sheets get cycled through
/*I need something here to find which column on row two says "Pass/Fail"*/
for(i=3;i<data.length;++i){ // iterate row by row and examine data in column A
//r.push("test2"); //Testing to make sure the all
if(data[i][7]=='Fail'){ r.push(data[i])}; // if column 7 contains 'fail' then add it to the list
}
}
return r; //Return row of failed results on all tabs
}
At first, it retrieves data at column g. It retrieves a result from the data. The result is 2 dimensional array. The index of each element of the 2D array means the sheet index. If the sheet doesn't include values in column g, the element length is 0.
For example, in the case of following situation,
Sheet 0 doesn't include values in column g.
Sheet 1 includes values in column g. There are "Fail" value at the row number of 3, 4, 5.
Sheet 2 includes values in column g. There are "Fail" value at the row number of 6, 7, 8.
The result (return r) becomes below.
[[], [3, 4, 5], [6, 7, 8]]
Sample script 1:
function combined() {
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var data =[];
sheets.forEach(function(ss){
try { // In the case of check all sheets, if new sheet is included in the spreadsheet, an error occurs. This ``try...catch`` is used to avoid the error.
data.push(ss.getRange(3, 7, ss.getLastRow(), 1).getValues());
} catch(e) {
data.push([]);
}
});
var r = [];
data.forEach(function(e1, i1){
var temp = [];
e1.forEach(function(e2, i2){
if (e2[0] == "Fail") temp.push(i2 + 3);
});
r.push(temp);
});
return r;
}
If I misunderstand your question, I'm sorry.