Creating a Macro in google spreadsheet to search and then write text - google-sheets

What I am trying to accomplish is I would like to search for a term in one cell, if that cell has the term write text to another cell. My specific example would be I would like to search for the term 'DSF' in column 4. If I find 'DSF' it would then write 'w' in column 5 & write '1.2' in column 3. This is searched per row.
I do understand the the .setvalue will write the needed text, but I do not understand how to create a search function. Some help would be greatly appreciated.
EDIT
Here is the code I am working with at the moment. I am modifying it from something I found.
function Recalls()
{
var sh = SpreadsheetApp.getActiveSheet();
var data = sh.getDataRange().getValues(); // read all data in the sheet
for(n=0;n<data.length;++n){ // iterate row by row and examine data in column D
if(data[n][3].toString().match('dsf')=='dsf'){ data[n][4] = 'w'}{ data[n][2] = '1.2'};// if column D contains 'dsf' then set value in index [4](E)[2](C)
}
//Logger.log(data)
//sh.getRange(1,1,data.length,data[3].length).setValues(data); // write back to the sheet
}
With the Logger.log(data) not using the // It works properly but it overwrites the sheet, which will not work since I have formulas placed in a lot of the cells. Also, Maybe I did not realize this but Is there a way to do a live update, as in once I enter text into a cell it will research the sheet? Otherwise having to 'run' the macro with not save me much time in the long run.

Try this. It runs when the sheet is edited. It only captures columns C,D,&E into the array and only writes back those columns. That should solve overwriting your formulas. It looks for 'DSF' or 'dsf' in column D (or contains dsf with other text in the same cell either case). Give it a try and let me know if I didn't understand your issue.
function onEdit(){
var sh = SpreadsheetApp.getActiveSheet();
var lr = sh.getLastRow()// get the last row number with data
var data = sh.getRange(2,3,lr,3).getValues(); // get only columns C.D,& E. Starting at row 2 thur the last row
//var data = sh.getDataRange().getValues();// read all data in the sheet
for(n=0;n<data.length-1;++n){ // iterate row by row and examine data in column D
// if(data[n][0].toString().match('dsf')=='dsf'){
if(data[n][1].match(/dfs/i)){ //changed to find either upper or lower case dfs or with other text in string.
data[n][2] = 'w';
data[n][0] = '1.2'};
}
sh.getRange(2,3,data.length,data[3].length).setValues(data); // write back to the sheet only Col C,D,& E
}

Related

Is there a way to use FILTER with multiple Sheets containing a specific phrase in Google Sheets?

I will try to be as clear as possible. Here is the example piece: link
What I want to happen is that the Filter formula will search for any Sheet containing “Form Responses” and then display the results. You can see on the Current sheet how I’ve been doing, but this is more tedious and leads to issues of the first formula begins to overwrite the next one, etc. On the Wanted tab, I’ve laid out how I imagine it and put a note in A7. Any help offered is greatly appreciated!
You can get started with this script:
function getSheetResponses(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Wanted");
var getCellValue = sheet.getRange("A7").getValue(); //Gets the name of your designated sheet on "Wanted Sheet" cell "A7"
var getName = ss.getSheetByName(getCellValue);
var getNameValue = getName.getRange(2,5,getName.getLastRow(),1).getValues(); //Gets all the values of Column E on any defined sheet names based on getCellValue
var datalength = getNameValue.length;
Logger.log(datalength);
sheet.getRange(8,6,datalength,1).setValues(getNameValue); //Puts the data on Wanted Sheet Column F
}
What this does is it gets the sheet name on cell A7, and populates the data on Column F row 8 on the "Wanted" sheet like so:
Now, the data it populates on the "Wanted" sheet came from Form Responses 1 based on the sample piece you have provided:
If ever you would want to relocate which specific row or column the data would be pasted on "Wanted" Sheet. You can refer to this documentation on how to modify the rows and columns on sheet.getRange()
Reference:
https://developers.google.com/apps-script/reference/spreadsheet/sheet#getrangerow,-column,-numrows,-numcolumns

Getting the range of a cell a function is launched from

I have got a dictionary from an URLfetch. What I want to do is write the values in the row the script is launched from, but I don't know how to navigate trough the cells.
So how to get the range of the cell a function is launched from?
Thanks
function separate(Json) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("JsonData");
// cell = range of the cell the function is launched from
sheet.getRange(x).setValue(0."currentvalue")
// where x is the value on the b columns of the same row
sheet.getRange(y).setValue(0."marketcap")
// where y is the value on the c columns of the same row
// repeating this for every value of the dictionary that I want in my sheet.
return Json.O."id" // write the id in the cell in which the function is launched from
}
Here is how I want to call the function
Dictionary in a list taken into argument as Json
I assume that you have the data being written vertically right now. If your goal is to write it horizontally, then you can use TRANSPOSE() around your function to transmute your column into a row-
UPDATE
The solution above will work in a formula based approach. If you want to use an Apps Script approach, you could do the following. First you have to familiarize yourself with Range.getValues() and Range.setValues(). The first method will read values from a given range. In this scenario it should be used to load the dictionary values into Apps Script and save them into an array. At this point you have an array with the dictionary values stored in a column-life fashion, but since you want them in a row-like fashion you should transpose the array. To do it easily you can use the function at the bottom. Now you can safely take your row-like array and paste it into the Sheet with Range.setValues(). Please write back with any doubt about this second answer.
function transposeArray(array) {
return array[0].map((col, i) => array.map(row => row[i]));
}

Find duplicate values in comma separated rows with random data

Your assistance will be greatly appreciated as I have been struggling with this for a while and couldn't find a solution.
I have a Google Sheets file with comma-separated data in two columns as per the screenshot attached.
Screenshot of the two columns
text from the screenshot:
soon,son,so,on,no N/A
kind,kid,din,ink,kin,in dink
sing,sign,sin,gin,in,is gis,ins,sig,gins
farm,arm,ram,far,mar,am arf
may,yam,am,my N/A
tulip,lip,lit,pit,put,tip piu,pul,til,tui,tup,litu,ptui,puli,uplit
gift,it,if,fit,fig gif,git
hear,are,ear,hare,era,her hae,rah,rhea
dish,his,is,hi,hid dis,ids,sidh
trip,pit,rip,tip,it N/A
wife,few,if,we fie
thaw,what,hat,at haw,taw,twa,wat,wha
red,deer,reed ere,dee,ree,dere,dree,rede
as,save,vase,sea ave,sae,sev,vas,aves
from,for,form,of,or fro,mor,rom
won,now,on,own,no N/A
sport,port,spot,post,stop,sort,top,opt,pot,pro tor,sotrot,ops,tors,tops,trop,pots,opts,rots,pros,prost,strop,ports
I would love to have in another column a formula to show if in these two columns there are any duplicate values.
Thank you in advance for your help... it's been weeks without success haha
If you have Excel for Windows O365 with the UNIQUE and FILTERXML functions,
and if you mean to consider both columns together as if they were a single piece of data,
then try:
=UNIQUE(FILTERXML("<t><s>" & SUBSTITUTE(TEXTJOIN("</s><s>",TRUE,$A$1:$A$17,$B$1:$B$17),",","</s><s>") & "</s></t>","//s[.=following-sibling::*]"))
If that is not what you want, please clarify your question.
First place your data in columns A and B of an Excel worksheet. Then run this short VBA macro:
Sub report()
Dim rng As Range, r As Range, c As Collection, K As Long
Set rng = Range("A1:B17")
Set c = New Collection
K = 1
For Each r In rng
arr = Split(r.Value, ",")
For Each a In arr
On Error Resume Next
c.Add a, CStr(a)
If Err.Number <> 0 Then
Err.Number = 0
Cells(K, "C").Value = a
K = K + 1
End If
On Error GoTo 0
Next a
Next r
Range("C:C").RemoveDuplicates Columns:=1, Header:=xlNo
Set c = Nothing
End Sub
The duplicates appear in column C
What I have understood from your question: you want to find out if there are any words delimited by commas matching between the cells of two different columns.
For this solution I have used Apps Script. The following commented piece of code will find matching words between the two columns. Moreover, as the function used is an onEdit() trigger, it will automatically detect any changes done in either of these columns and automatically find out new matches or matches that are no longer there and update the value of cell C1:
function onEdit() {
// get current sheet
var sheet = SpreadsheetApp.getActive().getActiveSheet();
// get values from our columns. This returns a 2D array that is flatten into a
// 1 D array to then convert it into a string where its elements are separated
// by a comma and white spaces are removed (so that a matches space + a for example)
var colA = sheet.getRange('A1:A2').getValues().flat().join().replace(/\s/g, '');
var colB = sheet.getRange('B1:B2').getValues().flat().join().replace(/\s/g, '');
// Create two arrays where each element is a word delimited by a comma in their original
// string
var ArrayA = colA.split(',');
var ArrayB = colB.split(',');
// find matches in these two arrays and return these matches
var matchingValues = ArrayA.filter(value => ArrayB.includes(value));
// set the value of C1 to the words that the filter has matched between our two columns
// join is used to display all the matching elements of the match array
sheet.getRange('C1').setValue(matchingValues.join());
}
Demo:
If you do not know how to open the script editor, you can access it on your Google Sheets menu bar under Tools-> Script editor.

Remove rows based on duplicates in a single column in Google Sheets

I have spreadsheet similar to this:
I'd like to remove all duplicates of row based on the first column data.
So from this screenshot row, 1 and 2 would be kept, and row 2 would be removed. Any help would be greatly appreciated.
P.S. In my case I have columns from A to AU and rows from 2 to 9500.
Thank you.
Maya's answer and the solution AJPerez linked both work.
You can also use Filter View, which doesn't require deleting rows or creating new rows/sheets.
First create a helper column, say to the left of all your data. If your data starts on row 1, then create a blank row above all your data; if not, you are fine. Afterwards, on the first row where you have data, say row 2, write in the formula
=iserror(match(B2,B$1:B1,0))
Replace "2" with the row number of the first row of your data and "1" with that number minus 1. Also populate the rest of the column with the formula. (Unfortunately, arrayformula doesn't work here.) The formula outputs TRUE when the entry in B# has not occurred in cells above.
Note that this assumes your data now starts with column B and column B is where you want the filter to base. If that's not the case, just edit the column index too accordingly.
Select this new helper column. Go to Data -> Filter Views... -> Create a new Filter. Select filter by value and check TRUE only.
Caveat: this filter can only work if there are actually rows with TRUE value. This will always be the case as some entries are always unique.
If you want to avoid the caveat in your future applications, you can use filter by conditions with custom formula. The formula b2 should work.
But to begin with, even without the helper column, the above formula should work. Why doesn't it? That would be a good question for Google Support should it exist.
You can also use a google apps script to do this. To open the script editor from google sheets:
Choose the menu Tools > Script Editor.
Copy and paste the following script:
function removeDuplicates() {
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
var newData = [];
var ids = [];
for (var i in data) {
var row = data[i];
var duplicate = false;
if (ids.indexOf(row[0]) > -1) {
duplicate = true;
} else {
duplicate = false;
ids.push(row[0]);
}
if (!duplicate) {
newData.push(row);
}
}
sheet.clearContents();
sheet.getRange(1, 1, newData.length, newData[0].length).setValues(newData);
}
This assumes that you want to dedupe based on the contents of the first row of you sheet. If not you can adjust the row references from the 0 index to any other index you wish.
I would...
Create a new sheet
For column A, do =Unique(Sheet1!A:A)
Simply use VLOOKUP to populate the other columns. This will deliver the first value associated with the duplicates.

arrayformula that can "skip" rows

I need to introduce functionality into a google spreadsheet that will allow the user to edit the result of an array formula. The reason for the requirement is that an ARRAYFORMULA sets a default value for a group of cells, but the user sometimes needs to overwite these defaults. I'd like to know if this is even remotely possible.
example:
Row(#)|Array_1 |Array_2
------------------------------------
1 |a |=arrayformula(Array_1)
2 |b |""
3 |c |""
4 |d |""
So all rows in Array_2 are populated by an array formula. However the user wants to go directly to the second cell in Array_2 and change its value. Of course, by design ARRAYFORMULA will break. Is there some way to modify ARRAYFORMULA, so that it will simply skip over the cell that the user has edited and continue on its way as if nothing has happeded?
I realize this is an old problem but I was searching for this today and made a script that works for me.
This script puts a formula in an adjacent cell when a cell is edited in the second column. This way you can just overwrite the formula if you need to input something manually and you don't need to have the formulas go into all of the rows beforehand. I had people accidentally edit the formula and mess it up most of the time when they were pre-filled, so this works better for me.
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetList = ["Sheet1","Sheet2","Sheet3"]; // list of sheets to run script on
for (i = 0; i < sheetList.length; i++) {
var sheetName = ss.getSheetByName(sheetList[i]);
// only runs if sheet from sheetList is found
if (sheetName != null) {
var aCell = sheetName.getActiveCell();
var col = aCell.getColumn();
var adjacentCell = aCell.offset(0, -1);
var formula = 'INPUT FORMULA HERE'; // put the formula you want in the adjacentCell here. Don't use it in an arrayformula
// only runs if active cell is in column 2, if the adjacentCell is empty, and if the active cell is not empty(otherwise it runs if you delete something in column 2)
if(col==2 && adjacentCell.getValue()=="" && aCell.getValue()!="") {
adjacentCell1.setValue(formula);
}
}
}
}
Will changing the value not throw out the output of the remaining formulas?
If not, you could set up 2 new tabs: one which will receive the user over-ride values, and another "reflection" tab which you populate with
IF(tabOverride!Rx:Cy, tabOverride!Rx:Cy, tabArray!Rx:Cy)
basically the new tabs are cloned layouts of your array tab, creating an override input layer, plus a presentation layer that uses the IF('override value exists', 'then show override', 'else show array out put') logic to return the desired values.
hope that makes sense!

Resources