Deleting Cells in Google Sheets without removing a whole row - google-apps-script

I have the code as below that currently deletes the entire row if 'delete' is in the 4th cell of that row. Is it posible to just delete the 3 cells to the left as well as the cell I have written 'delete' in, rather than the whole row (I have other content in Cell B16 for example I don't want to delete?
I haven't been able to find a .deleteCell function. Is there another way to do this?
function deleteRows() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var rowsDeleted = 0;
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
if (row[4] == 'delete') { // This searches all cells in columns A (change to row[1] for columns B and so on) and deletes row if cell is empty or has value 'delete'.
sheet.deleteRow((parseInt(i)+1) - rowsDeleted);
rowsDeleted++;
}
}
};

Delete with Shift Up or Shift Left
This will delete a cell and shift the data up or left depending upon the shift parameter.
function delCellAndShift(row,column,shift)
{
if(row && column)
{
var shift=(typeof(shift)!='undefined')?shift:'left';
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var rg=sh.getDataRange()
var vA=rg.getValues();
if(shift=='left')
{
var tA=vA[row-1];
tA.splice(column-1,1);
tA.push('');
vA[row-1]=tA;
rg.setValues(vA);
}
if(shift=='up')
{
var vB=Object.keys(vA[0]).map(function (c) { return vA.map(function (r) { return r[c]; }); });
var tA=vB[column-1];
tA.splice(row-1,1);
tA.push('');
vB[column-1]=tA;
vA=Object.keys(vB[0]).map(function (c) { return vB.map(function (r) { return r[c]; }); });
rg.setValues(vA);
}
}
else
{
var s='Invalid Inputs for delCellAndShift.<br /><input type="button" value="Close" onClick="google.script.host.close();" />';
var ui=HtmlService.createHtmlOutput(s);
SpreadsheetApp.getUi().showModalDialog(us, 'Invalid Inputs')
}
}
I tested it using the following functions to setup my data and run the main function.
function testDelCell()
{
delCellAndShift(3,7,'up');
}
function testsetupfordelcell()
{
var rs=10;
var cs=10;
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var rg=sh.getRange(1,1,rs,cs);
var vA=rg.getValues();
for(var i=0;i<rs;i++)
{
for(var j=0;j<cs;j++)
{
vA[i][j]=Utilities.formatString('%s,%s',i,j)
}
}
rg.setValues(vA);
}
This is a sample of it shifting left:
This is a sample of it shifting up:

So the problem is:
How do I move all the cells beneath a given cell one row up (overwriting the given cell value)?
The code to do this would be:
function deleteCell(sheet, cellx, celly){
var wholeSheet = SpreadsheetApp.openById(sheet).getRange("A1:F").getValues();
for(var i = celly; i<wholeSheet.length; i++){
wholeSheet[cellx][i] = wholeSheet[cellx][i+1];
}
SpreadsheetApp.openById(sheet).setValues(wholeSheet);
}

Related

Matching cell values in different Google Sheets

Users input text in cell A1 of sheet1. I want to find an exact match in column G of sheet2, and get the row of that match. I'm new to GAPS and wrote a script to find matches all on one sheet. How do I modify it to look at sheet2?
function rowOfMatch(){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var data = sheet.getDataRange().getValues();
var inputName = sheet.getRange("A1").getValue();
for(var i = 0; i<data.length;i++){
if(data[i][6] == inputName){ //[6] to search column G
Logger.log((i+1))
return i+1;
}
}
}
function runOne(){
var ss=SpreadsheetApp.getActive();
var sh1=ss.getSheetByName('Sheet1');
var sh2=ss.getSheetByName('Sheet2');
var rg1=sh1.getRange(1,1,sh1.getLastRow(),1);
var rg2=sh2.getRange(1,7,sh2.getLastRow(),1);
var v1=rg1.getValues();
var v2=rg2.getValues().map(function(r){return r[0];});
for(var i=0;i<v1.length;i++) {
var row=v2.indexOf(v1[i][0])+1;
if(row>0) {
sh1.getRange(i+1,2).setValue(row);
}else{
sh1.getRange(i+1,2).setValue('Not Found');
}
}
}
Animation:

duplicate row based on cell value

I want to duplicate row based on cell value then delete the cell value(in red) so that when rerun the script wont work on the same row again
I've tried script but it has 2 problems
1- the cell value remain so when rerun script it will cause duplication of same row again and again
2- remove the formulas that I wrote from the entire sheet
the script if you want to check it is still exist in appscript
https://docs.google.com/spreadsheets/d/1fJc2ymAADaZ4jtEGRAkUkWRape24Un7OE4jYcgcd9FM/edit#gid=0
Auto Dupe for Single Row
function AutoDuplicate() {
var ss=SpreadsheetApp.getActive()
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var vA=rg.getDisplayValues();
var bA=rg.getBackgrounds();
var v=[];
var b=[]
for(var i=0;i<vA.length;i++){
var t1=bA[i][7];
var t2=vA[i][7];
if(bA[i][7]=='#ff0000' && !isNaN(vA[i][7]) && Number(vA[i][7])>0) {
bA[i][7]='#ffffff';
for(var j=0;j<vA[i][7];j++) {
v.push(vA[i]);
}
b.push(bA[i]);
sh.getRange(1,1,v.length,v[0].length).setValues(v);
sh.getRange(1,1,b.length,b[0].length).setBackgrounds(b);
}
}
}
Animation:
Auto Dupe For Multiple Rows
function autoDupeForMultipleRows() {
var ss=SpreadsheetApp.getActive()
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var vA=rg.getDisplayValues();
var bA=rg.getBackgrounds();
var v=[];
var b=[];
var a=0;
for(var i=0;i<vA.length;i++){
if(bA[i][7]=='#ff0000' && !isNaN(vA[i][7]) && Number(vA[i][7])>0) {
bA[i][7]='#ffffff';
for(var j=0;j<=vA[i][7];j++) {
v.push(vA[i]);
b.push(bA[i]);
}
}
}
sh.clearContents();
var org=sh.getRange(1,1,v.length,v[0].length).setValues(v);
org.setBackgrounds(b);
}
Animation:

check if cell has value if not prompt dialog with error abort script if value then run script

I have searched on many forums yet and could not find this issue.
I have a script that moves a row from sheet 1 to sheet 2.
What I'm trying to achieve is that when a specific cell from sheet 1 is forgotten and left blank.
When I run the moverows() script I want to check if this row is has any empty cells and prompt with a dialog that there are still blank cells and abort the moverows() script if all the cells are not blank. Then proceed without a dialog.
I hope that you can point a direction or to a thread where there is a similar question.
I don't have enough knowledge to combine the dialog prompt with a check combine it with what I've got now:
function Moverows5() {
var ss = SpreadsheetApp.openById('sheetID');
var sourceSheet = ss.getSheetByName("sheetname1");
var targetSheet = ss.getSheetByName("sheetname 2");
var values = sourceSheet.getRange("B8:T43").getValues();
var range0 = sourceSheet.getRange("C8:K43");
var range1 = sourceSheet.getRange("Q8:T43");
var range2 = sourceSheet.getRange("P2");
var range3 = sourceSheet.getRange("R2");
var firstFreeRow = goToFirstRowAfterLastRowWithData(targetSheet, "A:AD");
//check column to whatever column you want to check
targetSheet.getRange(firstFreeRow, 1, values.length, values[0].length) .setValues(values);
range0.clearContent();
range1.clearContent();
range2.clearContent();
range3.clearContent();
createPdf()//function gets started
} //end of first function
function goToFirstRowAfterLastRowWithData(sheet, range) {
var v = sheet.getRange(range).getValues(),l = v.length,r;
while (l > 0) {
if (v[l] && v[l][0].toString().length > 0) {
r = (l + 2);
break;
} else {
l--;
}
}
return r ? r : 'no data found';
}
Check range for blanks before copying
This function checks the values array for blanks. If blanks are found it alerts the user, identifies the blank cells and terminates the function. Otherwise, it makes the transfer and clears some ranges.
function Moverows5() {
var ss=SpreadsheetApp.getActive();
var sourceSheet=ss.getSheetByName("Sheet1");
var targetSheet=ss.getSheetByName("Sheet2");
var sourceRange=sourceSheet.getRange("B8:T43");
var values=sourceRange.getValues();
var range0=sourceSheet.getRange("C8:K43");
var range1=sourceSheet.getRange("Q8:T43");
var range2=sourceSheet.getRange("P2");
var range3=sourceSheet.getRange("R2");
var firstFreeRow=targetSheet.getLastRow() + 1;
var noBlanks=true;
var bA=[];
var ro=sourceRange.getRow();
var co=sourceRange.getColumn();
for(var ri=0;ri<values.length;ri++) {
for(var ci=0;ci<values[ri].length;ci++) {
if(!values[ri][ci]) {
noBlanks=false;
bA.push(sourceSheet.getRange(ri+ro,ci+co).getA1Notation());
}
}
}
if(noBlanks) {
targetSheet.getRange(firstFreeRow,1,values.length,values[0].length).setValues(values);
range0.clearContent();
range1.clearContent();
range2.clearContent();
range3.clearContent();
//createPdf()//function gets started
}else{
SpreadsheetApp.getUi().alert('Sorry there are blanks in the following cells: ' + bA.join(', '));
return;
}
}
If you wish you may use this function to create some test data before testing on valuable spreadsheet.
function createTestData() {
var m=1;//0 for random column positions >0 for fixed position
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
sh.clearContents();
var cols=30;//number of columns
var rows=50;//number of rows
var hpref='hdr';
var hA=[];
var hdrA=[];
var cA=[];
for(var i=0;i<cols;i++) {hA.push(i+1);};
for(var i=0;i<cols;i++) {
if(m==0) {
var index=Math.floor(Math.random() * hA.length);
}else{
var index=i;
}
var hnum=hA[index];
hdrA.push(hpref + hnum);
cA.push(hnum);
if(m==0) {
hA.splice(index,1);
}
}
sh.getRange(1,1,1,hdrA.length).setValues([hdrA]);
var rg=sh.getRange(2,1,rows,cols);
var vA=rg.getValues();
for(var i=0;i<rows;i++) {
for(var j=0;j<cols;j++) {
vA[i][j]=Number(i+1) + ',' + cA[j];
}
}
rg.setValues(vA);
sh.getRange("B8:T43").setBackground('#ff00ff');
}

Change moverows script that checks blanks i a row to specific cells left blank in a row

Got help with my script from Cooper yet i need some modification, the script basically moverows with a custom dialog if a cell in the row is left blank.
What i like to accomplish is that only the specific cells in a row will be checked.
e.g. row 1 and 4 are mandatory and row 2 and 3 are not.
This is the code what I've got so far.
function Moverows57654() {
var ss=SpreadsheetApp.getActive();
var sourceSheet=ss.getSheetByName("sheet1");
var targetSheet=ss.getSheetByName("sheet2");
var sourceRange=sourceSheet.getRange("A2:T2");
var values=sourceRange.getValues();
var range0=sourceSheet.getRange("A2:B2");
var range1=sourceSheet.getRange("D2:E2");
var firstFreeRow=goToFirstRowAfterLastRowWithData(targetSheet, "A:AD");
var noBlanks=true;
var bA=[];
var ro=sourceRange.getRow();
var co=sourceRange.getColumn();
for(var ri=0;ri<values.length;ri++) {
for(var ci=0;ci<values[ri].length;ci++) {
if(!values[ri][ci]) {
noBlanks=false;
bA.push(sourceSheet.getRange(ri+ro,ci+co).getA1Notation());
}
}
}
if(noBlanks) {
targetSheet.getRange(firstFreeRow,1,values.length,values[0].length)
.setValues(values); targetSheet.getRange(firstFreeRow, 1, values.length, values[0].length)
.setValues(values);
range0.clearContent();
range1.clearContent();
//createPdf()//function gets started
}else{
SpreadsheetApp.getUi().alert('Sorry there are blanks in the following cells: ' + bA.join(', '));
return;
}
Try this:
function Moverows57654() {
var ss=SpreadsheetApp.getActive();
var sourceSheet=ss.getSheetByName("sheet1");
var targetSheet=ss.getSheetByName("sheet2");
var sourceRange=sourceSheet.getRange("A2:T2");
var values=sourceRange.getValues();
var range0=sourceSheet.getRange("A2:B2");
var range1=sourceSheet.getRange("D2:E2");
//var firstFreeRow=targetSheet.getLastRow() + 1;
var firstFreeRow=goToFirstRowAfterLastRowWithData(targetSheet, "A:AD");
var noBlanks=true;
var bA=[];
var skA=[1,2];//column -1
var ro=sourceRange.getRow();
var co=sourceRange.getColumn();
for(var ri=0;ri<values.length;ri++) {
for(var ci=0;ci<values[ri].length;ci++) {
if(!values[ri][ci] && skA.indexOf(ci)==-1) {
noBlanks=false;
bA.push(sourceSheet.getRange(ri+ro,ci+co).getA1Notation());
}
}
}
if(noBlanks) {
targetSheet.getRange(firstFreeRow,1,values.length,values[0].length)
.setValues(values); targetSheet.getRange(firstFreeRow, 1, values.length, values[0].length)
.setValues(values);
range0.clearContent();
range1.clearContent();
//createPdf()//function gets started
}else{
SpreadsheetApp.getUi().alert('Sorry there are blanks in the following cells: ' + bA.join(', '));
return;
}
}

How to remove duplicates per row and loop by column in Google Apps Scripts?

I have a set of data that is categorised by months every 3 columns. In other words, e.g. columns A to C is September, columns D to F is October and so on. I would like help on removing duplicates in each row for each month, so that if data in one row in columns A and B and C matches another row, the duplicate cells in that row is deleted. This is then repeated for the next month (next 3 columns D, E and F).
So far I've only managed to find scripts that remove duplicate rows in a specific range but not how to remove duplicate cells in rows and loop every few columns.
This is the code I have so far for removing duplicate rows in a specific range:
function deleteDuplicates() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = "Master";
var sourceSheet = ss.getSheetByName(source);
var sourceRange = sourceSheet.getRange(3, 1, sourceSheet.getLastRow(), 3)
var sourceData = sourceRange.getValues();
var keepData = new Array();
var deleteCount = 0;
for(i in sourceData) {
var row = sourceData[i];
var duplicate = false;
for(j in keepData) {
if(row[0] == keepData[j][0] &&
row[1] == keepData[j][1] &&
row[2] == keepData[j][2]) {
duplicate = true;
}
}
if(!duplicate) {
keepData.push(row);
}
}
sourceRange.clear();
sourceSheet.getRange(3, 1, keepData.length,
keepData[0].length).setValues(keepData);
}
I'm pretty new to scripting so any help with modifying this script or new inputs is greatly appreciated. Thanks.
Update: Here's an example data in my google sheets if it makes it clearer.
https://docs.google.com/spreadsheets/d/1IDcBlzFj6992RvMXS3TOyqaS5HsSRqjxk5HXsnYrGkA/
Try this:
There's probably a lot of easier ways to do it. But I liked the problem so here's a way to do it. This example generates is own random data so you need to take that out before running it on your dataset. But if I pasted it correctly and you copy it correctly and make a Sheet2 for it to work on then it should run okay for you. If not, please be prepared to debug it on your own.
By the way it also has some extraneous notes and result so that I could figure out if it was working or not. Good Luck. Also I haven't tried it but I don't think this cares if the months appear in consecutive columns.
function removeDupesInGroups(){
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Sheet2');
generateContent(3,1,100,9);
var rg=sh.getRange(1,1,sh.getLastRow(),9);
var vA=rg.getValues();
var hdr={};
var dA=[];
for(var j=0;j<vA[0].length;j++){
if(!hdr.hasOwnProperty(vA[0][j])){
hdr[vA[0][j]]=[];
hdr[vA[0][j]].push(j);
}else{
hdr[vA[0][j]].push(j);
}
}
var n=0;
for(key in hdr){
var m=key;
var uA=[];
for(var i=2;i<vA.length;i++){
var tA=[];
for(var j=0;j<vA[i].length;j++){
var elements=hdr[key].join(',');
if(hdr[key].indexOf(j)>-1){
tA.push(vA[i][j]);
}
}
if(i<vA.length){
if(!isArrayContained(uA,tA)){
uA.push(tA);
}else{
sh.deleteRow(i - n + 1);
dA.push([Utilities.formatString('n=%s,i=%s,deleeting row %s,key=%s,group=%s',n,i,i-n+1,key,tA.join('|'))]);
sh.getRange(1, 10).setValue(Utilities.formatString('n=%s,i=%s,deleeting row %s,group=%s',n,i,i-n+1,tA.join(',')));
n++;
}
}
}
}
var resultrg=sh.getRange(sh.getLastRow()+2,1,dA.length,1).setValues(dA);
}
function isArrayContained(c,t){
for(var i=0;i<c.length;i++){
var isEqual=true;
for(var j=0;j<c[i].length;j++){
var t1=c[i][j];
var t2=t[j];
if(c[i][j]!=t[j]){
isEqual=false;
break;
}
}
if(isEqual){
return true;
}
}
return false;
}
function generateContent(row,col,rows,cols){
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Sheet2');
sh.getDataRange().clearContent();
sh.getRange(1,1,2,9).setValues([['Jan','Jan','Jan','Feb','Feb','Feb','Mar','Mar','Mar'],['Header','Header','Header','Header','Header','Header','Header','Header','Header']])
var rg=sh.getRange(row,col,rows,cols);
var vA=rg.getValues();
var s="For the Lamb on the Throne will be their Shepard.";
for(var i=0;i<vA.length;i++){
for(var j=0;j<vA[i].length;j++){
vA[i][j]=s.charAt(Math.floor(Math.random() * s.length+1));
}
}
rg.setValues(vA);
}
Not sure if this is the most efficient, but I tried this amendment to my code and it works for my purposes with test data. Here's the final code I used.
function deleteDuplicates() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = "Master";
var sourceSheet = ss.getSheetByName(source);
for (var a=1; a<=19; a+=3){
var sourceRange = sourceSheet.getRange(3, a, sourceSheet.getLastRow(), 3)
var sourceData = sourceRange.getValues();
var keepData = new Array();
var deleteCount = 0;
for(i in sourceData) {
var row = sourceData[i];
var duplicate = false;
for(j in keepData) {
if(row[0] == keepData[j][0] &&
row[1] == keepData[j][1] &&
row[2] == keepData[j][2]) {
duplicate = true;
}
}
if(!duplicate) {
keepData.push(row);
}
}
sourceRange.clear();
sourceSheet.getRange(3, a, keepData.length,
keepData[0].length).setValues(keepData);
}
It basically starts at column a and adds 3 to it which changes the source range and loops until it reaches column 19.